个人理解:
- 在进行路由切换的过程就是导航;
- 设置导航,就在切换过程中进行限制,限制执行了,就是守卫成功了;
以下结合各路大神的总结,望海涵。
一、导航守卫的分类
1、有3种导航守卫
- 全局守卫
- 单个路由独享守卫
- 组件内的守卫
2、都有3个参数,除了 afterEach守卫(后面详解)
- to: 要进入的目标路由
- from: 离开当前的路由
- next: 控制路由执行(必须要有),一定要调用该方法来 resolve 这个钩子
3、next 4个行为:
next(); // 钩子执行完了,可以进入下一个路由;导航守卫的状态:confirmed
next(false); //中断当前路由跳转行为
next('/'); next({ path: '/' }) // 根据路由跳转条件来进入相应的路由,进入一个新的导航
next( new Error ) // 中断路由,错误会被传递给 router.onError() 注册过的回调中
二、3种导航守卫详解
1、全局路由守卫(有3个)
- 挂载到 router 实例上
- 用于控制路由的每一次跳转
1.1、beforeEach:全局前置守卫
const router = new VueRouter({ ... })
router.beforeEach((to, from, next) => {
// to 代表去的路由 a => b b就是去的路由
// from 代表来自于哪个路由 a => b a就是来自的路由
// next 控制路由的跳转与取消跳转
// 不加上 next ,页面跳转不了
// next() 执行跳转
// next(false) 取消跳转 a => b
// next 重新定向到某个页面 next("/login")
})
作用: 常用于登录验证
router.beforeEach((to, from, next) => {
if (to.name !== 'Login' && !isAuthenticated) next({ name: 'Login' })
else next()
})
1.2、beforeResolve:全局解析守卫
你可以用 router.beforeResolve
注册一个全局守卫。这和 router.beforeEach
类似,区别是在导航被确认之前,同时在所有组件内守卫和异步路由组件被解析之后,解析守卫就被调用。
1.3、afterEach:全局后置钩子守卫
这些钩子不会接受 next
函数也不会改变导航本身:
router.afterEach((to, from) => {
// ...
})
2、单个路由独享守卫(1个)
2.1、 beforeEnter
可以在路由配置上直接定义 beforeEnter
守卫;只有进入到当前页面才会执行的守卫函数;
const router = new VueRouter({
routes: [
{
path: '/foo',
component: Foo,
beforeEnter: (to, from, next) => {
// ...
}
}
]
})
3、组件内的守卫(3个)
3.1、beforeRouteEnter
- 在渲染该组件的对应路由被 confirm 前调用(大概意思:进入之前调用);
重点:
不能获取 this 实例。因为当守卫执行前,组件实例还没被创建;顺序:
beforeEach 和 独享守卫 beforeEnter 之后,全局 beforeResolve 和 afterEach 之前调用;
const Foo = {
template: `...`,
beforeRouteEnter(to, from, next) {
},
}
解决: beforeRouteEnter
守卫 不能 访问this
,因为守卫在导航确认前被调用,因此即将登场的新组件还没被创建。可以通过传一个回调给next
来访问组件实例。在导航被确认的时候执行回调,并且把组件实例作为回调方法的参数。
beforeRouteEnter (to, from, next) {
next(vm => {
// 通过 `vm` 访问组件实例
})
}
3.2、beforeRouteUpdate
- 在当前路由改变,但是该组件被复用时调用;
- 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用;
- 可以访问组件实例
this
const Foo = {
template: `...`
beforeRouteUpdate(to, from, next) {
},
}
3.3、beforeRouteLeave
- 导航离开该组件的对应路由时调用
- 可以访问组件实例
this
beforeRouteLeave(to, from, next) {
// 导航离开该组件的对应路由时调用
// 可以访问组件实例 `this`
}
beforeRouteLeave 使用场景:
- 当组件内有定时器,需要清除时,路由切换以免导致内存占用;
- 将公用信息保存到 session 或 vuex 中;
- 当页面有未关闭的窗口,或有未保存的时候,该导航可以通过
next(false)
来取消阻止页面跳转,示例如下:
beforeRouteLeave (to, from, next) {
const answer = window.confirm('Do you really want to leave? you have unsaved changes!')
if (answer) {
next()
} else {
next(false)
}
}
4、完整的导航解析
- 导航被触发。
- 在失活的组件里调用
beforeRouteLeave
守卫。 - 调用全局的
beforeEach
守卫。 - 在重用的组件里调用
beforeRouteUpdate
守卫 (2.2+)。 - 在路由配置里调用
beforeEnter
。 - 解析异步路由组件。
- 在被激活的组件里调用
beforeRouteEnter
。 - 调用全局的
beforeResolve
守卫 (2.5+)。 - 导航被确认。
- 调用全局的
afterEach
钩子。 - 触发 DOM 更新。
- 调用
beforeRouteEnter
守卫中传给next
的回调函数,创建好的组件实例会作为回调函数的参数传入。