前言

vue-router 有几种钩子函数?具体是什么及执行流程是怎样的?

思维导图:

dbc632da4d344c21bcf4a51eed789f2f_tplv-k3u1fbpfcp-zoom-in-crop-mark_3024_0_0_0 _1_.webp

vue-router 提供的导航守卫主要用来通过 跳转取消 的方式 守卫导航 。有多种机会植入路由导航过程中:全局的, 单个路由独享的, 或者组件级的。也就是:全局守卫路由守卫组件守卫

全局守卫

前置守卫 beforeEach

全局前置守卫,在路由跳转前触发,它在 每次导航 时都会触发。

1
2
3
4
5
router.beforeEach((to, from, next) => {
console.log('to:', to);
console.log('from:', from);
next();
})

beforeEach 全局前置守卫接收三个参数:

  1. to: Route: 即将要进入的目标路由对象
  2. from: Route: 当前导航正要离开的路由对象
  3. next: Function: 一定要调用该方法不然会阻塞路由

next 参数可以不添加,但是一旦添加,则必须调用一次,否则路由跳转等会停止。

next()方法的几种情况

  1. next(): 进行管道中的下一个钩子。
  2. next(false): 中断当前的导航。回到 from 路由对应的地址。
  3. next('/') 或者 next({ path: '/' }): 跳转到一个不同的地址,可传递的参数与 router.push 中选项一致。
  4. next(error): 导航终止,且该错误会被传递给 router.onError() 注册过的回调。

返回值:

  • false:取消当前的导航。
  • null,undefined,true或者直接return:调用下一个导航守卫。

解析守卫 beforeResolve

全局解析守卫,在路由跳转前,所有 组件内守卫异步路由组件 被解析之后触发,它同样在 每次导航 时都会触发。

通过 router.beforeResolve 注册一个全局解析守卫:

1
2
3
router.beforeResolve((to, from, next) => {
next();
})

回调参数,返回值和 beforeEach 一样。也可以定义多个全局解析守卫。

后置守卫 afterEach

全局后置钩子,它发生在路由跳转完成后,beforeEachbeforeResolve 之后,beforeRouteEnter(组件内守卫)之前。它同样在 每次导航 时都会触发。

通过 router.afterEach 注册一个全局后置钩子:

1
2
3
4
router.afterEach((to, from) => {
console.log('to:', to);
console.log('from:', from);
})

路由独享守卫 beforeEnter

路由守卫只有一个,就是 beforeEnterbeforeEnter 守卫 只在进入路由时触发,不会在 paramsqueryhash 改变时触发。

1
2
3
4
5
6
7
{
path: '/a',
component: () => import('../components/A.vue'),
beforeEnter: (to, from) => {
console.log('beforeEnter ');
},
}

组件守卫

beforeRouteEnter

1
2
3
4
5
beforeRouteEnter(to, from) {
// 在渲染该组件的对应路由被验证前调用
// 不能获取组件实例 `this` !
// 因为当守卫执行时,组件实例还没被创建!
},

beforeRouteEnter 守卫 不能 访问 this,因为守卫在导航确认前被调用,因此即将登场的新组件还没被创建。

不过,你可以通过传一个回调给 next 来访问组件实例。在导航被确认的时候执行回调,并且把组件实例作为回调方法的参数:

1
2
3
4
5
  beforeRouteEnter (to, from, next) {
next(vm => {
// 通过 `vm` 访问组件实例
})
}

beforeRouteUpdate

1
2
3
4
beforeRouteUpdate (to, from) {
// just use `this`
this.name = to.params.name
}

beforeRouteLeave

1
2
3
4
beforeRouteLeave (to, from) {
const answer = window.confirm('Do you really want to leave? you have unsaved changes!')
if (!answer) return false
}

beforeRouteEnter 是支持给 next 传递回调的唯一守卫。对于 beforeRouteUpdatebeforeRouteLeave 来说,this 已经可用了,所以不支持 传递回调,因为没有必要了

完整的导航解析流程

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