Vue Router 导航守卫
🌟 学习目标
掌握 Vue Router 中导航守卫的种类、执行顺序、使用场景及最佳实践,理解其在权限控制、数据获取和用户体验优化中的核心作用。
🔍 一、导航守卫类型概览
Vue Router 提供了多种粒度的导航守卫机制,用于拦截路由跳转并执行逻辑判断或异步操作。主要分为以下四类:
类型 | 执行时机 | 是否影响导航 | 典型用途 |
---|---|---|---|
全局前置守卫 beforeEach | 每次路由跳转前触发 | ✅ 可取消/重定向 | 权限验证、登录拦截 |
全局解析守卫 beforeResolve | 所有组件内守卫和异步组件加载后,导航确认前 | ✅ 可取消 | 数据预取、摄像头等权限请求 |
全局后置钩子 afterEach | 导航完成后调用 | ❌ 不可改变导航 | 页面统计、标题更新 |
路由独享守卫 beforeEnter | 特定路由进入前触发 | ✅ 可取消/重定向 | 单一路由级别的逻辑处理 |
组件内守卫 beforeRouteLeave/Update/Enter | 组件级别控制 | ✅ 可取消 | 表单未保存提示、复用组件更新 |
🧱 二、各类守卫详解
1. 全局前置守卫 router.beforeEach
✅ 功能说明
在任何路由切换前统一进行检查,常用于身份认证。
router.beforeEach(async (to, from) => {if (!isAuthenticated && to.name !== 'Login') {return { name: 'Login' } // 重定向到登录页}
})
返回值决定导航行为:
false
:取消导航路由对象(如
{ name: 'Login' }
):重定向undefined
/true
:继续导航
支持
async/await
和 Promise 异步解析
⚠️ 注意:避免重复调用
next()
,否则会导致钩子永不解析!
2. 全局解析守卫 router.beforeResolve
✅ 功能说明
在导航即将确认之前最后执行一次守卫,适合需要等待组件内部逻辑完成后再决策的场景。
router.beforeResolve(async to => {if (to.meta.requiresCamera) {const permission = await askForCameraPermission()if (!permission) return false}
})
执行时机晚于
beforeEach
和组件内守卫适用于依赖组件元信息或动态加载资源的权限校验
3. 全局后置钩子 router.afterEach
✅ 功能说明
仅用于“善后”操作,不参与导航流程控制。
router.afterEach((to, from, failure) => {if (!failure) {document.title = to.meta.title || 'App'sendToAnalytics(to.fullPath)}
})
接收第三个参数
failure
:表示导航是否失败常用于埋点、页面标题设置、日志记录
4. 路由独享守卫 beforeEnter
✅ 功能说明
定义在特定路由上的守卫,仅对该路由生效。
const routes = [{path: '/users/:id',component: UserDetails,beforeEnter: (to, from) => {if (!isValidId(to.params.id)) return false}}
]
不响应
params
、query
、hash
的变化(即复用组件时不触发)支持数组形式传入多个守卫函数,便于复用
beforeEnter: [removeQueryParams, removeHash]
5. 组件内守卫
(1)beforeRouteEnter
不能访问
this
(组件尚未创建)支持通过
next(vm => {})
在回调中获取实例
beforeRouteEnter(to, from, next) {next(vm => {vm.fetchData(to.params.id)})
}
(2)beforeRouteUpdate
当前组件被复用时触发(如
/users/1
→/users/2
)可直接访问
this
beforeRouteUpdate(to, from) {this.userId = to.params.idthis.fetchData()
}
(3)beforeRouteLeave
离开当前路由前触发,可用于防止用户意外离开
beforeRouteLeave(to, from) {if (this.hasUnsavedChanges) {const confirm = window.confirm('你有未保存的更改,确定要离开吗?')if (!confirm) return false}
}
💡 使用组合式 API 时可用
onBeforeRouteLeave
和onBeforeRouteUpdate
钩子。
⏳ 三、完整导航解析流程(执行顺序)
下面是整个导航从触发到完成的所有步骤,按执行顺序排列:
📌 关键点总结:
守卫是异步队列,必须全部 resolve 才能进入下一步
beforeResolve
是最后一个可以阻止导航的机会afterEach
不会阻塞流程,即使抛出错误也不会影响导航
🔐 四、实际应用场景示例
场景1:用户登录权限控制
router.beforeEach(async (to, from) => {const requiresAuth = to.matched.some(record => record.meta.requiresAuth)const isAuthenticated = await checkAuth()if (requiresAuth && !isAuthenticated) {return { name: 'Login', query: { redirect: to.fullPath } }}
})
场景2:页面离开前确认
<script>
export default {data() {return {hasUnsavedChanges: true}},beforeRouteLeave(to, from) {if (this.hasUnsavedChanges) {return window.confirm('你的修改尚未保存,确定要离开吗?')}}
}
</script>
场景3:动态标题设置
router.afterEach((to) => {document.title = to.meta.title ? `${to.meta.title} - MyApp` : 'MyApp'
})
场景4:全局注入使用(Vue 3.3+)
// main.ts
app.provide('apiBase', 'https://api.example.com')// router.ts
router.beforeEach(() => {const apiBase = inject('apiBase')const store = useUserStore() // Pinia Store// 进行业务逻辑判断...
})
📚 五、知识点详解
知识点1:导航守卫的异步解析机制
每个守卫可返回 Promise 或使用 async/await,所有守卫 resolve 后才继续导航。若任一守卫 reject 或返回 false
,则中断导航。
字数:49
知识点2:beforeRouteEnter
中无法访问 this
因组件尚未实例化,故不能访问实例属性。需通过 next(vm => {...})
在回调中获取
字数:47
知识点3:完整的导航流程顺序
导航经历离开原组件 → 全局前置 → 路由独享 → 解析异步组件 → 进入新组件 → 最终确认 → DOM 更新 → 回调执行。
字数:48
✅ 六、最佳实践与注意事项
实践建议 | 说明 |
---|---|
✅ 使用 meta 字段标记路由需求 | 如 meta: { requiresAuth: true, title: '用户中心' } |
✅ 避免在 beforeEach 中做耗时操作 | 否则会影响首屏加载体验 |
✅ 合理利用 beforeResolve 获取数据 | 在最终确认前拉取必要数据 |
✅ 组件内守卫优先使用组合式 API | 更符合 Vue 3 设计哲学 |
✅ 防止无限重定向循环 | 判断目标路由是否为登录页再重定向 |
✅ 利用 failure 参数处理失败导航 | 在 afterEach 中捕获异常情况 |
🎯 七、总结图示(文字版流程图)
📝 结语
Vue Router 的导航守卫系统提供了强大而灵活的路由控制能力,合理运用可以在不侵入业务逻辑的前提下实现权限管理、用户体验优化和性能提升。建议结合 meta
字段、Pinia 状态管理和异步加载机制,构建健壮的前端路由体系。