导航守卫
所谓的导航守卫,就是路由的钩子函数。主要用来通过跳转或取消导航。导航守卫分三种:全局、路由独享、组件级的。
注意:参数或查询的改变并不会触发进入和离开的导航守卫。可以通过watch
监听$route
对象,或使用beforeRouteUpdate
的组件内守卫。
全局前置守卫
进入路由之前的钩子函数,接受next
函数,在此可以阻止进入路由或跳转到指定路由。
<script>
const router = new VueRouter({ ... });
// 接收三个参数:to为目标路由对象信息,from为当前路由对象信息,next则为是否继续
router.beforeEach((to, from, next) => {
// ...
});
</script>
全局解析钩子
router.beforeResolve((to, from, next) => {
// 区别是在导航被确认之前,同时在所有组件内守卫和异步路由组件被解析之后 调用
});
全局后置钩子
允许进入路由触发,和守卫不同的是,不接受next
函数也不会改变导航本身。
<script>
router.afterEach((to, from) => {
// 一般用于改变页面的title
});
</script>
路由独享的守卫
在路由配置上直接定义beforeEnter
守卫,表示:进入路由之前
<script>
const router = new VueRouter({
routes: [
{
path: '/foo',
component: Foo,
beforeEnter: (to, from, next) => {
// 进入路由之前
}
}
]
});
</script>
组件内的守卫
const Foo = {
template: `...`,
beforeRouteEnter (to, from, next) {
// 1. 在渲染该组件的对应路由被 确定 前调用
// 2. 不能 获取组件实例 this,因为执行该守卫时,组件实例还没被创建
// 3. 是支持给 next 方法传递回调的唯一守卫,可以通过回调访问组件实例
next(vm => {
// 通过 vm 访问组件实例
});
},
beforeRouteUpdate (to, from, next) {
// 1. 在当前路由改变,但是该组件被复用时调用
// 举例:对于一个带有动态参数的路径 /foo/:id, 在/foo/1 和/foo/2之间跳转的时候,由于会渲染同样的Foo组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
// 2. 可以访问组件实例 this
next();
},
beforeRouteLeave (to, from, next) {
// 1. 导航离开该组件的对应路由时调用
// 2. 可以访问组件实例 this
// 通常用来禁止用户在还未保存修改前突然离开,该导航可以通过 next(false) 来取消
const answer = window.confirm('确定离开?');
if (answer) {
next();
}else{
next(false); // 取消导航跳转
}
}
}
守卫和钩子的参数
- to: 即将要进入的目标路由对象
- from: 当前导航的路由对象
- next: 通过该方法来守卫导航是否进入,还是中断,或进入指定导航
- next() 进入管道中的下一个钩子,全部钩子执行完了,则导航的状态就是确定的
- next(false) 表示中断当前的导航。如果浏览器的
URL
改变了,那么URL
地址会重置到from
路由对应的地址 - next('/') 或 next({ path:'/' }) 跳转到指定地址
注意: 在导航守卫中确保要调用next
方法,否则不会继续执行
完整的导航解析流程
- 导航被触发
- 在失活的组件里调用离开守卫
- 调用全局的
beforeEach
守卫 - 在重用的组件里调用
beforeRouteUpdate
- 在路由配置里调用
beforeEnter
- 解析异步路由组件
- 在被激活的组件里调用
beforeRouteEnter
- 调用全局的
beforeResolve
- 导航被确认
- 调用全局的
afterEach
钩子 - 触发
DOM
更新 - 用创建好的实例调用
beforeRouteEnter
守卫中传给next
的回调函数