Skip to content

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()
})

六、注意事项

  1. 一定要调用 next()

    • 前置守卫中必须调用 next()
    • 否则路由会被卡住
  2. 避免死循环

    • 重定向时要注意条件判断
    • 防止无限重定向
  3. 性能考虑

    • 守卫中的操作要尽量轻量
    • 避免过多的异步操作
  4. 错误处理

    • 要做好错误捕获
    • 确保进度条正确结束