Vue Router 路由守卫详解
一、什么是路由守卫?
路由守卫是 Vue Router 提供的一种导航控制机制,用于:
- 登录验证
- 权限控制
- 页面跳转控制
- 数据预加载等
二、路由守卫类型
2.1 全局守卫
beforeEach
: 全局前置守卫 在每个路由跳转之前触发,可以用来进行登录验证、权限控制等操作。 设置路由前置守卫,通过 meta 属性,判断 to 路由是否需要权限校验afterEach
: 全局后置守卫 在每个路由跳转之后触发,通常用于执行后置操作,如修改页面标题、添加页面跟踪、记录页面浏览历史等。beforeResolve
: 全局解析守卫 在全局前置守卫之后、路由被确认之前触发,可以用来进行数据预加载等操作。 避免请求数据出错导致的程序崩溃
2.2 路由独享守卫
beforeEnter
: 在路由配置上直接定义
2.3 组件内守卫
主要用于处理组件级别的逻辑,如数据预加载、生命周期钩子、权限控制等。
beforeRouteEnter
当前路由开始之前调用,不能访问 this,因为组件实例还没有创建。 用于组件被创建之前获取数据或执行初始化操作beforeRouteUpdate
在当前路由改变,该组件被复用时调用,比如一个组件在多个路由之间切换时、用于组件数据更新时执行操作;可以访问 this,因为组件实例已经创建。beforeRouteLeave
当前路由即将离开时调用,用于组件离开时执行操作,比如询问用户是否保存数据,可以访问 thisi。
三、实际应用示例
3.1 基本配置
javascript
import NProgress from 'nprogress' // 进度条
import 'nprogress/nprogress.css'
import { useLoginStore } from '@/store/modules/userlogin'
// 白名单:不需要登录就能访问的路由
const whiteList = ['/login']
export function setupRouterGuard(router) {
// 配置 NProgress
NProgress.configure({ showSpinner: false })
// 前置守卫
router.beforeEach((to, from, next) => {
NProgress.start() // 开始进度条
const store = useLoginStore()
const token = store.token
if (token) {
// 已登录状态
if (to.path === '/login') {
// 已登录还想访问登录页,重定向到首页
next('/CompanyLicense')
NProgress.done()
} else {
// 正常访问其他页面
next()
}
} else {
// 未登录状态
if (whiteList.includes(to.path)) {
// 在白名单中的路由,允许访问
next()
} else {
// 不在白名单中的路由,重定向到登录页
next('/login')
NProgress.done()
}
}
})
// 后置守卫
router.afterEach(() => {
NProgress.done() // 结束进度条
})
// 错误处理
router.onError((error) => {
console.error('路由错误:', error)
NProgress.done()
})
}
避免页面跳转时加载时间过长,因此使用了进度条nprogress来提示用户加载进度,进而提升用户体验。
3.2 在 main.js 中使用
javascript
import { setupRouterGuard } from './router/guard'
// 初始化路由守卫
setupRouterGuard(router)
四、路由守卫参数说明
4.1 beforeEach 的参数
to
: 即将要进入的目标路由对象from
: 当前导航正要离开的路由对象next
: 必须调用的函数,决定导航行为next()
: 继续导航next(false)
: 中断导航next('/path')
: 重定向到其他路由next(error)
: 导航会被中断,错误会被传递
4.2 afterEach 的参数
to
: 已经进入的路由对象from
: 已经离开的路由对象- 不需要 next 函数
五、最佳实践
5.1 权限控制
javascript
router.beforeEach((to, from, next) => {
if (to.meta.requiresAuth && !isAuthenticated) {
next('/login')
} else {
next()
}
})
5.2 数据预加载
javascript
router.beforeEach(async (to, from, next) => {
if (to.meta.requiresData) {
await loadData()
}
next()
})
5.3 进度条控制
javascript
router.beforeEach((to, from, next) => {
NProgress.start()
next()
})
router.afterEach(() => {
NProgress.done()
})
六、注意事项
一定要调用 next()
- 前置守卫中必须调用 next()
- 否则路由会被卡住
避免死循环
- 重定向时要注意条件判断
- 防止无限重定向
性能考虑
- 守卫中的操作要尽量轻量
- 避免过多的异步操作
错误处理
- 要做好错误捕获
- 确保进度条正确结束