阿里云主机折上折
  • 微信号
您当前的位置:网站首页 > 路由导航守卫变化

路由导航守卫变化

作者:陈川 阅读数:23903人阅读 分类: Vue.js

路由导航守卫是Vue Router的核心功能之一,它允许开发者在路由切换的不同阶段注入逻辑,实现权限控制、数据预加载等场景。随着Vue 2到Vue 3的升级,导航守卫的API和行为也发生了显著变化。

导航守卫的基本类型

Vue Router提供了三种主要导航守卫:

  1. 全局守卫:作用于所有路由

    • router.beforeEach
    • router.beforeResolve
    • router.afterEach
  2. 路由独享守卫:在路由配置中定义

    • beforeEnter
  3. 组件内守卫:在组件选项中定义

    • beforeRouteEnter
    • beforeRouteUpdate
    • beforeRouteLeave
// 全局前置守卫示例
router.beforeEach((to, from, next) => {
  if (to.meta.requiresAuth && !store.state.isAuthenticated) {
    next('/login')
  } else {
    next()
  }
})

Vue 2中的导航守卫

在Vue 2中,导航守卫主要通过函数参数中的next方法控制流程:

// Vue 2风格的守卫
beforeRouteEnter(to, from, next) {
  getData(to.params.id, (data) => {
    next(vm => {
      vm.data = data
    })
  })
}

典型特点包括:

  • 必须调用next()继续流程
  • beforeRouteEnter是唯一无法访问this的守卫
  • 错误处理通过next(error)实现

Vue 3中的重大变化

Vue 3引入了Composition API,导航守卫也相应进行了现代化改造:

1. 返回值替代next

现在可以直接返回布尔值或路由位置:

router.beforeEach((to, from) => {
  if (to.meta.requiresAuth && !auth.isAuthenticated()) {
    return '/login'
  }
  // 隐式返回undefined等同于调用next()
})

2. 异步守卫支持

可以更自然地使用async/await:

router.beforeEach(async (to) => {
  if (to.meta.requiredData) {
    try {
      await store.dispatch('fetchInitialData')
    } catch (err) {
      return false // 中止导航
    }
  }
})

3. 组件内守卫的Composition API

在setup()中使用onBeforeRouteUpdate等函数:

import { onBeforeRouteLeave } from 'vue-router'

export default {
  setup() {
    onBeforeRouteLeave((to, from) => {
      if (formData.value.isDirty) {
        return confirm('确定要离开吗?')
      }
    })
  }
}

导航解析流程的变化

Vue 3优化了导航解析顺序:

  1. 触发失活组件的beforeRouteLeave
  2. 调用全局beforeEach
  3. 在重用的组件中调用beforeRouteUpdate
  4. 调用路由配置中的beforeEnter
  5. 解析异步路由组件
  6. 调用激活组件的beforeRouteEnter
  7. 调用全局beforeResolve
  8. 导航确认
  9. 调用全局afterEach

常见问题解决方案

1. 权限控制模式

// 动态路由场景下的权限处理
router.beforeEach(async (to) => {
  if (!auth.initialized) {
    await auth.initialize()
  }
  
  if (to.meta.roles && !auth.hasAnyRole(to.meta.roles)) {
    return { path: '/403', query: { originalPath: to.fullPath } }
  }
})

2. 数据预加载策略

// 路由独享守卫中的数据预取
const routes = [{
  path: '/user/:id',
  component: UserDetail,
  async beforeEnter(to) {
    const user = await fetchUser(to.params.id)
    to.meta.user = user // 传递给组件
  }
}]

3. 滚动行为集成

router.afterEach((to) => {
  if (to.meta.scrollToTop) {
    window.scrollTo({ top: 0 })
  }
})

性能优化技巧

  1. 守卫去重:避免在全局守卫中重复相同逻辑
  2. 懒加载优化:配合路由懒加载使用守卫
  3. 缓存策略:对频繁访问的路由实施缓存
// 缓存已验证路由
const routeCache = new Set()

router.beforeEach((to) => {
  if (routeCache.has(to.path)) return true
  
  if (needsValidation(to)) {
    return validate(to).then(() => {
      routeCache.add(to.path)
    })
  }
})

与Pinia的状态集成

在Vue 3生态中,与Pinia配合使用的模式:

import { useAuthStore } from '@/stores/auth'

router.beforeEach((to) => {
  const auth = useAuthStore()
  if (to.meta.requiresAdmin && !auth.isAdmin) {
    return { name: 'unauthorized' }
  }
})

测试导航守卫

使用Vue Test Utils测试守卫的示例:

import { mount } from '@vue/test-utils'
import { createRouter, createWebHistory } from 'vue-router'

test('blocks unauthorized access', async () => {
  const router = createRouter({
    history: createWebHistory(),
    routes: [{ path: '/admin', meta: { requiresAuth: true } }]
  })
  
  router.beforeEach((to) => {
    if (to.meta.requiresAuth) return '/login'
  })
  
  await router.push('/admin')
  expect(router.currentRoute.value.path).toBe('/login')
})

调试技巧

  1. 使用路由元信息标记调试:
router.beforeEach((to) => {
  console.log('[Navigation]', to.meta.guardDebug ? 
    `Debug: ${to.name}` : 
    `Navigating to ${to.path}`)
})
  1. 开发环境专用守卫:
if (import.meta.env.DEV) {
  router.beforeEach(logNavigation)
}

迁移注意事项

从Vue 2迁移到Vue 3时需注意:

  1. 移除所有显式的next()调用
  2. 转换回调风格为Promise/async风格
  3. 更新组件内守卫到Composition API
  4. 检查依赖导航顺序的副作用
// 迁移前 (Vue 2)
beforeRouteLeave(to, from, next) {
  if (this.hasChanges) {
    next(confirm('Discard changes?'))
  } else {
    next()
  }
}

// 迁移后 (Vue 3)
onBeforeRouteLeave(() => {
  return !hasChanges.value || confirm('Discard changes?')
})

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

前端川

前端川,陈川的代码茶馆🍵,专治各种不服的Bug退散符💻,日常贩卖秃头警告级的开发心得🛠️,附赠一行代码笑十年的摸鱼宝典🐟,偶尔掉落咖啡杯里泡开的像素级浪漫☕。‌