跳转到内容

Vue Router导航守卫

来自代码酷


Vue Router导航守卫是Vue Router提供的一种机制,允许开发者通过钩子函数在路由导航过程中进行拦截和控制。这些守卫可以用于权限验证、页面访问控制、数据预加载等场景,为单页应用(SPA)提供了更精细的路由控制能力。

导航守卫概述[编辑 | 编辑源代码]

导航守卫分为三类,按触发顺序排列如下:

1. 全局守卫:作用于所有路由 2. 路由独享守卫:只作用于特定路由 3. 组件内守卫:在路由组件内定义

导航解析流程可以用以下mermaid图表示:

flowchart LR A[导航触发] --> B[调用离开守卫] B --> C[调用全局前置守卫] C --> D[调用路由独享守卫] D --> E[调用组件内守卫] E --> F[确认导航] F --> G[调用全局后置钩子]

全局守卫[编辑 | 编辑源代码]

全局守卫通过router实例直接注册,包含以下三种:

beforeEach[编辑 | 编辑源代码]

在导航触发前调用,常用于权限验证。

router.beforeEach((to, from, next) => {
  // to: 即将进入的目标路由
  // from: 当前导航正要离开的路由
  // next: 必须调用此函数来resolve这个钩子
  if (to.meta.requiresAuth && !isAuthenticated()) {
    next('/login')
  } else {
    next() // 继续导航
  }
})

beforeResolve[编辑 | 编辑源代码]

在导航被确认前调用,适合确保异步操作完成。

router.beforeResolve(async to => {
  if (to.meta.fetchData) {
    await fetchDataBeforeEnter(to.params.id)
  }
})

afterEach[编辑 | 编辑源代码]

导航完成后调用,没有next参数。

router.afterEach((to, from) => {
  logNavigation(to.path, from.path)
})

路由独享守卫[编辑 | 编辑源代码]

直接在路由配置中定义:

const routes = [
  {
    path: '/admin',
    component: AdminPanel,
    beforeEnter: (to, from, next) => {
      if (user.role !== 'admin') {
        next('/forbidden')
      } else {
        next()
      }
    }
  }
]

组件内守卫[编辑 | 编辑源代码]

在路由组件内定义:

beforeRouteEnter[编辑 | 编辑源代码]

在渲染该组件的对应路由被确认前调用,不能访问组件实例(this)。

beforeRouteEnter(to, from, next) {
  next(vm => {
    // 通过vm访问组件实例
    vm.loadData(to.params.id)
  })
}

beforeRouteUpdate[编辑 | 编辑源代码]

在当前路由改变但组件被复用时调用。

beforeRouteUpdate(to, from, next) {
  this.userId = to.params.id
  this.fetchUserData()
  next()
}

beforeRouteLeave[编辑 | 编辑源代码]

在导航离开该组件的对应路由时调用。

beforeRouteLeave(to, from, next) {
  if (this.unsavedChanges) {
    if (confirm('有未保存的更改,确定离开?')) {
      next()
    } else {
      next(false)
    }
  } else {
    next()
  }
}

完整导航解析流程[编辑 | 编辑源代码]

1. 导航被触发 2. 调用即将离开组件的beforeRouteLeave 3. 调用全局的beforeEach 4. 在重用的组件里调用beforeRouteUpdate 5. 调用路由配置里的beforeEnter 6. 解析异步路由组件 7. 调用即将进入组件的beforeRouteEnter 8. 调用全局的beforeResolve 9. 导航被确认 10. 调用全局的afterEach 11. 触发DOM更新 12. 执行beforeRouteEnter中传给next的回调函数

实际应用案例[编辑 | 编辑源代码]

案例1:权限控制[编辑 | 编辑源代码]

router.beforeEach((to, from, next) => {
  const publicPages = ['/login', '/register']
  const authRequired = !publicPages.includes(to.path)
  const loggedIn = localStorage.getItem('user')
  
  if (authRequired && !loggedIn) {
    return next('/login')
  }
  
  next()
})

案例2:页面访问统计[编辑 | 编辑源代码]

router.afterEach((to, from) => {
  analytics.trackPageView(to.path)
})

案例3:动态标题[编辑 | 编辑源代码]

router.beforeEach((to, from, next) => {
  document.title = to.meta.title || '默认标题'
  next()
})

数学公式示例[编辑 | 编辑源代码]

如果需要计算导航耗时,可以使用以下公式:

Tnav=TbeforeEach+TbeforeEnter+TbeforeRouteEnter+Trender

其中:

  • TbeforeEach 是全局前置守卫执行时间
  • TbeforeEnter 是路由独享守卫执行时间
  • TbeforeRouteEnter 是组件内守卫执行时间
  • Trender 是组件渲染时间

注意事项[编辑 | 编辑源代码]

1. 确保总是调用next(),否则钩子不会resolved 2. 在beforeRouteEnter中无法访问this,因为组件实例还未创建 3. 导航守卫是异步执行的 4. 可以使用next(false)中止当前导航 5. 可以使用next('/path')或next({ path: '/path' })重定向

通过合理使用导航守卫,开发者可以构建更安全、更高效的单页应用,实现复杂的路由控制逻辑。