10、Vue 3 - Vue Router 使用实录 : 路由守卫

作者: 温新

图书: 【Vue 3 Vue Router 使用实录】

阅读: 34

时间: 2024-05-19 17:27:17

Vue 3 中的 Vue Router 路由守卫是一种强大的功能,允许你在路由跳转过程中的不同阶段执行逻辑,比如权限检查、页面过渡控制等。

Vue Router 提供了全局前置拦截全局后置拦截单个路由拦截 的功能。

路由守卫机制

  • 全局前置拦截:beforeEach((to,from, next) => {}),此时,路由未跳转
  • 全局后置拦截:afterEach((to,from,next) => {}),此时,路由已跳转
  • 单个路由拦截:beforeEnter((to,from,next) => {}),需要配置在路由中

参数说明:

  • to:要跳转的目标路由

  • from:从当前哪个路由进行跳转

  • next 函数

    • next() 表示放行,允许此次路由导航

    • next(false) 表示不放行,不允许此次路由导航

    • next({name:routerPath}) 表示导航到该路由

单个路由拦截

本次将演示 单个路由拦截全局前置路由拦截

1、添加组件

src/views/LoginView.vue

<template>
    <h3>登录</h3>
</template>

<script setup lang="ts">
</script>
2、实现单个路由拦截

注意:单个路由的拦截,其使用位置是在路由中进行拦截。

src/router/index.ts

...

const router = createRouter({
    history: createWebHistory(),
    routes:[
		...
        
        {
            path:'/login',
            name:'login',
            component: () => import('@/views/LoginView.vue'),
            meta:{
                'title':'登录',
            },
            // 拦截登录路由
            beforeEnter: (to, from ,next) => {
                console.log('单个拦截');
                console.log(to);
                // 放行路由,如果没有 next() 函数,路由将不会跳转
                next()
            }
        },
    ]
})

...
3、测试

访问 http://localhost:5173/home 页面,打开 F12 ,然后点击 登录 按钮,并观察控制台中输出的信息。

全局前置路由拦截

演示全局前置路由时,我就不在添加新的路由及文件了。使用的是之前已经创建的路由及文件。

1、路由预览

注意:全局前置、后置拦截都需要在 router 对象上使用。

src/router/index.ts

import { createRouter, createWebHistory } from "vue-router"

const router = createRouter({
    history: createWebHistory(),
    routes:[
        {
            path:'/',
            redirect:'/home'
        },
        {
            path:'/home',
            name:'home',
            component: () => import('@/views/HomeView.vue'),
            meta:{
                'title':'首页',
            },
            children:[
                {
                    path:'/home/contact',
                    name:'联系我',
                    components: {
                        contact:() => import('@/views/ContactView.vue')
                    }
                },
                {
                    path:'/home/category',
                    name:'分类',
                    components: {
                        category:() => import('@/views/CategoryView.vue')
                    }
                }
            ]
        },
        {
            path:'/about',
            name:'about',
            component: () => import('@/views/AboutView.vue'),
            meta:{
                'title':'关于'
            },
            children: [
                {
                    path:'/about/post/:id',
                    name:"Post",
                    component: () => import('@/views/PostView.vue'),
                    props:true
                }
            ]
        },
        {
            path:'/:patchMatch(.*)',
            name:'404',
            component: () => import('@/views/404.vue')   
        },
        {
            path:'/login',
            name:'login',
            component: () => import('@/views/LoginView.vue'),
            meta:{
                'title':'登录',
            },
            // 拦截登录路由
            beforeEnter: (to, from ,next) => {
                console.log(to);
                next()
            }
        },
    ]
})

export default router
2、使用全局前置路由

src/router/index.ts

...

// 全局前置拦截
router.beforeEach((to, from, next) => {
    console.log('全局拦截');
    console.log(to);

    if (to?.meta?.title) {
        document.title = '自如初-' + to.meta.title
    }

    next()
})

...

你应用要注意到,此时,存在两个拦截器。

3、测试

首先打开 F12,访问 http://localhost:5173/home/ 并观察控制台的输出,此时,已经输出了相关信息。因为访问 home,它自身就是一个路由,自然就要被拦截到咯。

点击关于我按钮,再次看到相关信息的输出,此时,浏览器页面的 title 也发生了对应的变化。

4、前置和单个拦截,谁先生效?

上面提到有两个拦截器,前置拦截和单个拦截的问题,那么,当两个同时存在时,谁生效呢?不妨先猜测一下。

现在,我们回到首页 http://localhost:5173/home,并清空控制台中的输出,然后点击登录 按钮,观察控制台中的输出,如下:

全局拦截
...
单个拦截
...

这个输出,如你所想吗?

关于后置拦截就不演示了,代码如下:

// src/router/index.ts

// 全局后置拦截
router.afterEach((to,from,next) => {
    console.log('后置拦截');
    console.log(to);
})

本系列到此结束,文档中没有记录到的,如有需要,后续补充。

请登录后再评论