🌟 学习目标
掌握 Vue Router 中导航守卫的种类、执行顺序、使用场景及最佳实践,理解其在权限控制、数据获取和用户体验优化中的核心作用。
🔍 一、导航守卫类型概览
Vue Router 提供了多种粒度的导航守卫机制,用于拦截路由跳转并执行逻辑判断或异步操作。主要分为以下四类:
| 类型 | 执行时机 | 是否影响导航 | 典型用途 |
|---|---|---|---|
全局前置守卫 beforeEach |
每次路由跳转前触发 | ✅ 可取消/重定向 | 权限验证、登录拦截 |
全局解析守卫 beforeResolve |
所有组件内守卫和异步组件加载后,导航确认前 | ✅ 可取消 | 数据预取、摄像头等权限请求 |
全局后置钩子 afterEach |
导航完成后调用 | ❌ 不可改变导航 | 页面统计、标题更新 |
路由独享守卫 beforeEnter |
特定路由进入前触发 | ✅ 可取消/重定向 | 单一路由级别的逻辑处理 |
组件内守卫 beforeRouteLeave/Update/Enter |
组件级别控制 | ✅ 可取消 | 表单未保存提示、复用组件更新 |
🧱 二、各类守卫详解
1. 全局前置守卫 router.beforeEach
✅ 功能说明
在任何路由切换前统一进行检查,常用于身份认证。
javascript
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
✅ 功能说明
在导航即将确认之前最后执行一次守卫,适合需要等待组件内部逻辑完成后再决策的场景。
javascript
router.beforeResolve(async to => {
if (to.meta.requiresCamera) {
const permission = await askForCameraPermission()
if (!permission) return false
}
})
-
执行时机晚于 beforeEach 和组件内守卫
-
适用于依赖组件元信息或动态加载资源的权限校验
3. 全局后置钩子 router.afterEach
✅ 功能说明
仅用于"善后"操作,不参与导航流程控制。
javascript
router.afterEach((to, from, failure) => {
if (!failure) {
document.title = to.meta.title || 'App'
sendToAnalytics(to.fullPath)
}
})
-
接收第三个参数 failure:表示导航是否失败
-
常用于埋点、页面标题设置、日志记录
4. 路由独享守卫 beforeEnter
✅ 功能说明
定义在特定路由上的守卫,仅对该路由生效。
javascript
const routes = [
{
path: '/users/:id',
component: UserDetails,
beforeEnter: (to, from) => {
if (!isValidId(to.params.id)) return false
}
}
]
-
不响应 params、query、hash 的变化(即复用组件时不触发)
-
支持数组形式传入多个守卫函数,便于复用
javascript
beforeEnter: [removeQueryParams, removeHash]
5. 组件内守卫
(1)beforeRouteEnter
-
不能访问 this(组件尚未创建)
-
支持通过 next(vm => {}) 在回调中获取实例
javascript
beforeRouteEnter(to, from, next) {
next(vm => {
vm.fetchData(to.params.id)
})
}
(2)beforeRouteUpdate
-
当前组件被复用时触发(如
/users/1→/users/2) -
可直接访问 this
javascript
beforeRouteUpdate(to, from) {
this.userId = to.params.id
this.fetchData()
}
(3)beforeRouteLeave
- 离开当前路由前触发,可用于防止用户意外离开
javascript
beforeRouteLeave(to, from) {
if (this.hasUnsavedChanges) {
const confirm = window.confirm('你有未保存的更改,确定要离开吗?')
if (!confirm) return false
}
}
💡 使用组合式 API 时可用
onBeforeRouteLeave和onBeforeRouteUpdate钩子。
⏳ 三、完整导航解析流程(执行顺序)
下面是整个导航从触发到完成的所有步骤,按执行顺序排列:

📌 关键点总结:
-
守卫是异步队列,必须全部 resolve 才能进入下一步
-
beforeResolve 是最后一个可以阻止导航的机会
-
afterEach 不会阻塞流程,即使抛出错误也不会影响导航
🔐 四、实际应用场景示例
场景1:用户登录权限控制
javascript
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:页面离开前确认
javascript
<script>
export default {
data() {
return {
hasUnsavedChanges: true
}
},
beforeRouteLeave(to, from) {
if (this.hasUnsavedChanges) {
return window.confirm('你的修改尚未保存,确定要离开吗?')
}
}
}
</script>
场景3:动态标题设置
javascript
router.afterEach((to) => {
document.title = to.meta.title ? `${to.meta.title} - MyApp` : 'MyApp'
})
场景4:全局注入使用(Vue 3.3+)
javascript
// 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 状态管理和异步加载机制,构建健壮的前端路由体系。