导航守卫
1. 环境准备
1.1 安装Element-Plus
npm install element-plus
1.2 注册Element-Plush
需要在 main.ts 文件中注册
import { createApp } from 'vue'
import App from './App.vue'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
createApp(App).use(ElementPlus).mount('#app')
1.3 定义组件
定义一个首页组件
<template>
<div>首页</div>
</template>
<script setup lang="ts">
</script>
再创建一个登录组件:
<template>
<div class="login">
登录
</div>
</template>
<script setup lang="ts">
import {ref} from 'vue'
</script>
<style lang="less" scoped>
.login {
height: 100%;
display: flex;
justify-content: center;
}
</style>
1.4 配置路由
在 src 目录,新建 router 目录,然后创建 index.ts 路由配置文件。
import {createRouter, createWebHashHistory, RouteRecordRaw} from "vue-router";
const routes: Array<RouteRecordRaw> = [
{
path: '/',
alias: ['/index'],
component: () => import('../views/Index.vue'),
},
{
path: '/login',
component: () => import('../views/Login.vue'),
}
]
const router = createRouter({
history: createWebHashHistory(),
routes,
})
export default router
1.5 挂载路由
在 main.ts 文件中挂载路由。
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
createApp(App).use(router).use(ElementPlus).mount('#app')
1.6 定义入口
在根组件 App.vue 中使用路由
<template>
<router-view></router-view>
</template>
<script setup lang="ts">
</script>
<style>
* {
padding: 0;
margin: 0;
}
html,body,#app {
width: 100%;
height: 100%;
}
</style>
2. 完善登录
<template>
<div class="login">
<!-- 1. 添加登录的表单 -->
<el-card class="box-card">
<span>登录</span>
<!-- 3. 把数据和表单进行绑定 -->
<el-form ref="userFormRef" :model="user" :rules="rules" label-width="60px">
<!-- 9. 绑定校验规则,1)在 el-form 中添加 :rules="rules" 2)在 el-form-item 中添加 prop 属性 -->
<el-form-item label="账号" prop="account">
<!-- 4. 把输入框与数据(表单对象)绑定 -->
<el-input type="text" v-model="user.account" placeholder="账号"></el-input>
</el-form-item>
<el-form-item label="密码" prop="password">
<el-input type="password" v-model="user.password" placeholder="密码"></el-input>
</el-form-item>
<el-form-item>
<!-- 5. 添加表表单提交事件 -->
<el-button type="primary" @click="onSubmit(userFormRef)">登录</el-button>
<el-button @click="onReset(userFormRef)">取消</el-button>
</el-form-item>
</el-form>
</el-card>
</div>
</template>
<script setup lang="ts">
import {reactive, ref} from 'vue'
import {ElMessage, FormItemRule} from 'element-plus'
import type { FormInstance } from 'element-plus'
const userFormRef = ref<FormInstance>()
type User = {
account: string,
password: string,
}
const user = reactive<User>({
account: '',
password: '',
})
const onSubmit = (formEl: FormInstance | undefined) => {
formEl?.validate(valid => {
if (valid) {
console.log(user)
localStorage.setItem('token', JSON.stringify(user))
ElMessage.success('登录成功!')
} else {
ElMessage.error('登录失败!')
}
})
}
const onReset = (formEl: FormInstance | undefined) => {
console.log('-------111--------' + formEl)
if (!formEl) return
formEl.resetFields()
}
type Rules = {
[key in keyof User]?: Array<FormItemRule>
}
const rules = reactive<Rules>({
account: [
{
required: true,
message: '账号不能为空!',
type: 'string',
trigger: 'blur',
}
],
password: [
{
required: true,
message: '密码不能为空!',
type: 'string',
trigger: 'blur',
},
{
min: 6,
max: 16,
message: `密码的长度在 6 和 16 之间`,
trigger: 'blur',
}
]
})
</script>
<style lang="less" scoped>
.login {
margin-top: 20px;
display: flex;
justify-content: center;
.box-card {
width: 480px;
text-align: center;
span {
display: block;
font-size: 24px;
margin-bottom: 15px;
}
}
}
</style>
3. 导航守卫
在 main.ts 文件中添加导航守卫的配置
const whiteList = ['/']
router.beforeEach((to, from, next) => {
if (whiteList.includes(to.path) || localStorage.getItem('token')) {
next()
} else {
next('/')
}
})
每个守卫方法接收三个参数: to: Route,即将要进入的目标,路由对象; from: Route,当前导航正要离开的路由; next(): 进行管道中的下一个钩子。如果全部钩子执行完了,则导航的状态就是 confirmed (确认的)。 next(false): 中断当前的导航。如果浏览器的 URL 改变了 (可能是用户手动或者浏览器后退按钮),那么 URL 地址会重置到 from 路由对应的地址。 next(‘/’) 或者 next({ path: ‘/’ }): 跳转到一个不同的地址。当前的导航被中断,然后进行一个新的导航。
2. 路由元信息
在路由配置列表中通过 meta 属性来配置路由元信息。
{
path: '/index',
component: () => import('../views/Index.vue'),
meta: {
title: '首页标题'
}
},
3. 动态路由
对路由的添加通常是通过 routes 选项来完成的,但是在某些情况下,你可能想在应用程序已经运行的时候添加或删除路由。具有可扩展接口(如 Vue CLI UI )这样的应用程序可以使用它来扩展应用程序。
3.1 编写后端
3.1.1 创建一个后端项目
在IDE中创建一个目录,如:router-server 来作为后端项目的名称。
3.1.2 安装依赖
npm init -y
npm install ts-node -g
npm install @types/node -D
npm install express
npm install @types/express -D
3.1.3 编写基础服务
在项目的根目录下新建 index.ts 文件,代码如下:
import express, {Express, Request, Response} from 'express'
const app: Express = express()
app.get('/login', (req: Request, res: Response) => {
res.header('Access-Control-Allow-Origin', '*')
if (req.query.account === 'admin' && req.query.password === '123456') {
res.json({
route: [
{
path: '/demo01',
name: 'Demo01',
component: 'Demo01.vue'
},
{
path: '/demo02',
name: 'Demo02',
component: 'Demo02.vue'
},
{
path: '/demo03',
name: 'Demo03',
component: 'Demo03.vue'
}
]
})
} else if (req.query.account === 'jock' && req.query.password === '123456') {
res.json({
route: [
{
path: '/demo01',
name: 'Demo01',
component: 'Demo01.vue'
},
{
path: '/demo02',
name: 'Demo02',
component: 'Demo02.vue'
}
]
})
} else {
res.json({
code: 400,
message: '账号或密码错误!'
})
}
})
app.listen(9999, () => {
console.log('Local: http://localhost:9999')
})
3.1.4 配置服务
修改 package.json 文件,在 scripts 标签中定义启动项目的执行脚本。
{
"scripts": {
"dev": "ts-node index.ts",
"test": "echo \"Error: no test specified\" && exit 1"
}
}
3.1.5 启动服务
做完以上操作后,执行如下命令来启动服务。
npm run dev
3.2 编写前端
3.2.1 创建组件
在项目中创建 Demo01.vue、Demo02.vue 和 Demo03.vue 这三个组件,它们初始代码如下:
<template>
<h3>Demo01</h3>
</template>
<script setup lang="ts">
</script>
<style scoped>
</style>
3.2.2 安装axios
由于我们需要异步请求服务端来进行登录,因些,我们需要安装 axios 来实现异步操作。
npm install axios
3.2.3 实现登录
安装好 axios 后,在登录组件 Login.vue 中使用。
import axios from 'axios'
const initRouter = async () => {
const result = await axios.get('http://localhost:9999/login', { params: user })
console.log(result)
}
const onSubmit = (formEl: FormInstance | undefined) => {
formEl?.validate(valid => {
if (valid) {
console.log(user)
localStorage.setItem('token', JSON.stringify(user))
ElMessage.success('登录成功!')
initRouter()
} else {
ElMessage.error('登录失败!')
}
})
}
3.2.4 添加路由
把从服务端响应回来的数据添加到路由中,这时需要使用到 router.addRoute() 和 router.removeRoute() 这两个动态路由对象方法。
const initRouter = async () => {
const result = await axios.get('http://localhost:9999/login', { params: user })
result.data.route.forEach((v: any) => {
router.addRoute({
path: v.path,
name: v.name,
component: () => import(`./${v.component}`)
})
})
router.push('/index')
}
|