vue路由第三篇-导航守卫、路由元信息、动态路由

导航守卫

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'

// 10. 实现重置功能 1)需要在 el-form 标签上指定 ref="userFormRef" 2)在事件中把 userFormRef 以参数的方式传递给事件对象 3)在声明一个 userFormRef 响应式对象
const userFormRef = ref<FormInstance>()

// 定义类型
type User = {
    account: string,
    password: string,
}
// 2. 定义数据
const user = reactive<User>({
    account: '',
    password: '',
})
// 6. 实现事件
const onSubmit = (formEl: FormInstance | undefined) => {
    // 11. 实现提交时校验表单
    //console.log(user)
    formEl?.validate(valid => {
        //console.log(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() // 重置方法
}

// 7. 定义校验器类型
type Rules = {
    [key in keyof User]?: Array<FormItemRule>
}
// 8. 定义校验规则
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',
        //alias: ['/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 # 生成 package.json

npm install ts-node -g

# node.js 声明文件
npm install @types/node -D

npm install express

# 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', '*')

    // 验证登录是否存在,假设账号为 admin 密码为 123456
    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)
}

// 6. 实现事件
const onSubmit = (formEl: FormInstance | undefined) => {
    // 11. 实现提交时校验表单
    //console.log(user)
    formEl?.validate(valid => {
        //console.log(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 })
    //console.log(result)
    //console.log(result.data)
    result.data.route.forEach((v: any) => {
        // 动态添加路由
        router.addRoute({
            path: v.path,
            name: v.name,
            component: () => import(`./${v.component}`)
        })
    })

    // 跳转到首页
    router.push('/index')
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值