前言
在 Vue 项目中,路由守卫是控制页面权限、处理跳转逻辑的核心。无论是全局登录鉴权,还是组件内的特殊状态判断,熟练掌握路由守卫都是前端开发的必备技能。本文将从基础概念出发,带你拆解路由守卫的分类及其在企业级项目中的实战应用。
一、 路由守卫全解析
路由守卫的核心作用是在路由跳转过程中执行特定的逻辑(如权限校验、数据预取)。
1. 全局路由守卫
全局守卫直接挂载在 router 实例上,对应用内的所有路由跳转生效。
beforeEach(to, from, next):最常用。在路由跳转前触发,常用于登录状态校验。beforeResolve(to, from, next):在导航被确认之前,且组件内守卫和异步路由组件被解析之后调用。afterEach(to, from):在路由跳转完成后触发。注意: 它不接受next函数,也不会改变导航。
参数说明:
to: 即将要进入的目标路由对象。from: 当前正要离开的路由对象。next: 决定导航的行为。next()放行;next(false)中止;next('/path')重定向。
2. 组件内的路由守卫
直接定义在 .vue 组件内部,针对特定组件生效。
beforeRouteEnter:路由进入该组件前调用。此时拿不到组件实例this,因为组件实例还没被创建。该钩子在全局守卫beforeEach之后,全局守卫afterEach之前调用。beforeRouteUpdate:当前路由改变,且该组件被复用时调用(例如/user/1跳转到/user/2)。beforeRouteLeave:导航离开该组件时调用。常用于“离开前未保存”的选择提醒。
二、 使用示例:权限鉴权流
在真实项目中,我们通常将路由配置与守卫逻辑拆分。
1. 路由实例配置 (router/index.ts)
import { createRouter, createWebHashHistory, RouteRecordRaw } from 'vue-router'
import staticRoutes from './routes'
const router = createRouter({
history: createWebHashHistory(),
routes: staticRoutes as RouteRecordRaw[],
// 关键:切换页面后自动滚动到顶部
scrollBehavior: () => ({ left: 0, top: 0 })
})
export default router
2. 路由表定义 (router/routes.ts)
import { RouteRecordRaw } from 'vue-router'
const routes: RouteRecordRaw[] = [
{
path: '/login',
name: 'xxxx-登录',
component: () => import('@/views/login/index.vue')
},
{
path: '/',
component: () => import('@/views/layout/index.vue'),
redirect: '/home',
children: [
{
path: 'home', // 建议子路由使用相对路径
name: 'xxxxx-主页',
component: () => import('@/views/home/index.vue')
}
]
}
]
export default routes
3. 全局权限校验 (permission.ts)
在 main.ts 中引入此文件,确保守卫逻辑生效。
import router from './router'
import { getAccessToken } from '@/libs/utils/auth'
import { getPublicToken } from '@/libs/utils/dmAuth'
import { DM_SITEID } from '@/config/assistant'
// 路由白名单:不需要登录即可访问
const whiteList: string[] = ['/login']
// 全局前置守卫
router.beforeEach(async (to, from, next) => {
const token = getAccessToken()
const publicToken = getPublicToken(DM_SITEID)
// 判断是否具备双重 Token(业务 Token 与 对话管理 Token)
if (token && publicToken) {
if (to.path === '/login') {
next({ path: '/' }) // 已登录状态访问登录页,直接重定向到首页
} else {
next()
}
} else {
// 处理未登录情况
if (whiteList.includes(to.path)) {
next() // 白名单页面,直接放行
} else {
// 携带当前页面地址,方便登录后回跳
next(`/login?redirect=${to.fullPath}`)
}
}
})
// 全局后置守卫
router.afterEach((to) => {
// 动态修改页面标题
if (to.name) {
document.title = to.name as string
}
window.scrollTo(0, 0)
})