Vue Router 导航守卫 (Navigation Guards) 详解
Vue Router 的导航守卫主要用来通过跳转或取消的方式守卫导航。有多种机会植入路由导航过程中:全局的、单个路由独享的、或者组件级的。
一、 导航守卫的种类
导航守卫主要分为三类,它们的执行时机和作用域各不相同:
- 全局守卫 (Global Guards):影响每一次路由跳转。
- 路由独享守卫 (Per-Route Guards):只在特定路由配置中生效。
- 组件内守卫 (In-Component Guards):直接在组件内部定义,与组件生命周期紧密相关。
二、 全局守卫 (Global Guards)
全局守卫直接在 router 实例上操作。
1. 全局前置守卫 router.beforeEach
这是最常用的守卫类型,在每次路由切换之前被调用。
- 使用场景:登录验证、权限校验等。
- 代码示例:javascript
const router = new VueRouter({ ... }); router.beforeEach((to, from, next) => { // to: Route 即将要进入的目标 路由对象 // from: Route 当前导航正要离开的 路由对象 // next: Function 一个必须被调用的函数,用来 resolve 这个钩子 }); next函数详解:next(): 一切正常,继续进行导航,进入to所指向的路由。next(false): 中断当前的导航。URL 地址会重置到from路由对应的地址。next('/path')或next({ path: '/path' }): 中断当前导航,并进行一个新的导航。next(new Error()): 中断导航,并且错误会被传递给router.onError()注册的回调。
- 重要:务必确保
next函数在任何情况下都被且仅被调用一次。
2. 全局解析守卫 router.beforeResolve
这个守卫和 beforeEach 非常相似,也在每次导航前触发。
- 区别:它在导航被确认之前,所有组件内守卫和异步路由组件被解析之后被调用。
- 代码示例:javascript
router.beforeResolve((to, from, next) => { // ... });
3. 全局后置钩子 router.afterEach
与守卫不同,后置钩子在导航已经完成后被调用,因此它不会接受 next 函数,也不能改变导航本身。
- 使用场景:分析、滚动页面、页面加载动画结束等。
- 代码示例:javascript
router.afterEach((to, from) => { // 该钩子没有 next 函数,因为它无法改变导航 });
三、 路由独享守卫 (Per-Route Guard)
你可以在路由配置上直接定义 beforeEnter 守卫,它只在该路由被进入时触发。
- 代码示例:javascript
const router = new VueRouter({ routes: [ { path: '/admin', component: Admin, // 定义路由独享的守卫 beforeEnter: (to, from, next) => { // ... } } ] }); - 特点:参数和用法与全局前置守卫完全相同,但作用域被限定在单个路由规则内。
四、 组件内守卫 (In-Component Guards)
可以直接在路由组件内部定义导航守卫。
1. beforeRouteEnter(to, from, next)
- 时机:在渲染该组件的对应路由被确认前调用。
- 关键特点:此时组件实例还未被创建,因此不能获取组件实例
this。 - 访问实例:如果想在导航确认后访问组件实例,可以通过向
next传递一个回调函数来实现。javascriptexport default { beforeRouteEnter(to, from, next) { // 在这里无法访问 `this` next(vm => { // 通过 `vm` 访问组件实例 // vm 就是 this }); } }
2. beforeRouteUpdate(to, from, next)
- 时机:当路由改变,但该组件被复用时调用。
- 使用场景:例如,对于一个带有动态参数的路径
/user/:id,在/user/1和/user/2之间跳转时,User组件实例会被复用,这个钩子就会被调用。 - 特点:可以访问组件实例
this。
3. beforeRouteLeave(to, from, next)
- 时机:导航离开该组件的对应路由时调用。
- 使用场景:通常用于提醒用户保存修改,防止未保存的数据丢失。
- 特点:可以访问组件实例
this。
五、 完整的导航解析流程
当一个导航被触发时,会按照以下顺序依次调用各个守卫和钩子:
- 导航被触发。
- 在失活的组件里调用
beforeRouteLeave守卫。 - 调用全局的
beforeEach守卫。 - 在重用的组件里调用
beforeRouteUpdate守卫 (如果组件被复用)。 - 在路由配置里调用
beforeEnter守卫。 - 解析异步路由组件(如果需要)。
- 在被激活的组件里调用
beforeRouteEnter守卫。 - 调用全局的
beforeResolve守卫。 - 导航被确认。
- 调用全局的
afterEach钩子。 - 触发 DOM 更新。
- 调用在
beforeRouteEnter守卫中传给next的回调函数,创建好的组件实例会作为回调函数的参数传入。