导航守卫

所谓的导航守卫,就是路由的钩子函数。主要用来通过跳转取消导航。导航守卫分三种:全局、路由独享、组件级的

注意:参数或查询的改变并不会触发进入和离开的导航守卫。可以通过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方法,否则不会继续执行

完整的导航解析流程

  1. 导航被触发
  2. 在失活的组件里调用离开守卫
  3. 调用全局的beforeEach守卫
  4. 在重用的组件里调用beforeRouteUpdate
  5. 在路由配置里调用beforeEnter
  6. 解析异步路由组件
  7. 在被激活的组件里调用beforeRouteEnter
  8. 调用全局的beforeResolve
  9. 导航被确认
  10. 调用全局的afterEach钩子
  11. 触发DOM更新
  12. 用创建好的实例调用beforeRouteEnter守卫中传给next的回调函数