全解析:Vue路由提供的导航守卫
引入
正如其名,vue-router
提供的导航守卫主要用来通过跳转或取消的方式守卫导航,它们提供了在路由跳转前后执行某些逻辑的能力。
导航守卫主要分为三类:全局守卫、独享守卫和组件内的守卫。
全局守卫
每个守卫方法都要接收两个参数to和from,你也可以选择性的使用第三个参数next:
to
:即将要进入的目标from
:当前导航正要离开的路由next
:这是一个可选择是否要使用的第三个参数,如果要使用next,那么必须确保它在任何一个导航守卫中都只被严格调用一次。它可以出现多于一次,但是只能在所有的逻辑路径都不重叠的情况下,否则守卫永远都不会被解析或直接报错。 next的用法如下:
next()
: 表示允许跳转至目标路由。next ('/login')
或next( { name: 'login' } )
: 表示跳转到登录页面
1. 全局前置守卫:
全局前置守卫是通过router.beforeEach()
注册的,它会在导航触发时被调用。如果你注册了多个全局前置守卫,那么会按照创建顺序调用。因为守卫是异步解析执行,所以在所有守卫解析完之前,导航会一直处于等待中。
我们可以用这个守卫实现检查是否登录,权限验证等功能。下面是一段代码示例:
const router = createRouter({...})
router.beforeEach( (to,from,next) =>{
//检查用户是否登录
if(! user.isLoggedIn && to.path !== '/login'){
next('/login');
}else{
next();
}
});
router.beforeEach()
还可以有返回值:
false
: 取消当前要跳转前往的导航。- 一个路由地址 : 中断当前导航,并重定向到返回的路由地址。
router.beforeEach((to,from,next) =>{
...
return ('/login')
})
2.全局解析守卫
全局解析守卫是通过router.beforeResolve
注册的,它和全局前置守卫类似,都是在路由跳转之前触发,不同的是,它会在导航被确认前,同时在所有组件内守卫和异步路由组件被解析之后被调用。
使用全局解析守卫可以在路由跳转确认前的最后阶段进行一些额外的处理或检查,例如进一步验证权限、处理异步数据获取等操作。
3.全局后置钩子
全局后置钩子可以通过router.afterEach()
注册,它和其他守卫不同,它不接收next
,也不会改变导航本身,它会在路由跳转完成之后触发。我们可以用这个钩子实现更改页面标题,滚动条回到顶部等操作。
路由独享守卫
路由独享守卫beforeEnter
是针对单个路由的守卫,它在路由配置上被定义,且它只在进入该路由时被触发,不会在 params
、query
或 hash
改变时触发。
const router = new createRouter({
routes:[
{
path: './user/:id',
component: User,
beforeEnter(to, from, next) =>{
if(...){
next();//允许路由跳转
}else{
next(false);
}
}
}
]
})
组件内守卫
我们可以在组件内直接定义守卫,这个守卫是传递给该路由对应的路由配置的。
1. beforeRouteEnter
beforeRouteEnter
会在该组件的对应路由被confirm前调用,所以此时该组件的实例还没有创建,我们也就无法使用组件实例的this
。但是我们可以通过传一个回调给next
来访问组件实例,这个回调会在路由被确认时执行,并且把组件实例作为回调的参数。
<script>
export dafault{
beforeRouteEnter(to, from, next){
...
next(vm => {
//通过vm访问实例
})
}
}
</script>
2.beforeRouteUpdate
beforeRouteUpdate
会在当前路由改变,但该组件被复用时调用。例如:对于一个带有动态参数的路径 /foo/:id
,在 /foo/1
和 /foo/2
之间跳转时,由于会渲染同样的 foo
组件,因此组件实例会被复用,这个钩子就会在这种情况下被调用。因为该情况下组件已经挂载好了,所以在该钩子中可以访问组件实例 this
。
export default{
beforeRouteUpdate(to, from, next) {
this.name = to.params.name;
next();
}
}
3.beforeRouteLeave
beforeRouteLeave
会在导航离开当前组件对应的路由时调用,所以它可以访问组件实例this
。这个钩子通常用来防止用户还没有保存修改就突然离开,此时我们可以通过next(false)
来取消导航。例如:
export default{
beforeRouteLeave(to, from, next) {
const answer = window.confirm('你确认要离开吗?你还有未保存的更改!')
if(answer){
next();
}else{
next(false);
}
}
}
导航解析流程
在了解完这些路由守卫之后,我们再过一遍完整的导航解析流程:
- 导航被触发 : 比如使用了
<router-link>
组件或着直接调用router.push
或router.replace
方法。 - 在失活的组件中调用
beforeRouteLeave
守卫(如果有的话): 失活的组件就是即将不被展示的组件,为了防止用户还没有保存修改就离开,所以调用这个钩子。 - 调用全局的beforeEach守卫: 导航被触发时就会执行这个钩子。
- 在重用的组件内调用
beforeRouteUpdate
守卫 - 在路由配置里调用
beforeEnter
守卫(如果有的话):此时开始进入路由,beforeEnter
守卫会在进入路由时被调用。 - 解析异步路由组件
- 在被激活的组件里调用
beforeRouteEnter
: 这个钩子会在组件对应的路由被确认之前被调用。 - 调用全局的
beforeResolve
守卫: 这个钩子在路由被确认前,在所有组件内守卫和异步路由组件被解析后调用。 - 导航被确认
- 调用全局的
afterEach
钩子 - 触发 DOM 更新
- 调用
beforeRouteEnter
守卫中传给next
的回调函数,组件实例会作为回调函数的参数传入
转载自:https://juejin.cn/post/7394795454582341672