阅读 71

Vue-router 中的导航守卫

应用的导航需要“守卫”

Vue-router中你点击一个按钮,移步到了另外一个“网页”中。这是经常发生的事情。

在这个移步的过程当中,其实我们拥有着很多机会对这个行为做一些事情。

例如:小明打算从家里去外婆家,你在路上可以把他的腿打断,送回家,这样你就阻止了他去外婆家了。

小明去外婆家就是导航,你就是导航守卫。

  • 全局前置守卫

你可以使用 router.beforeEach 注册一个全局前置守卫:

const router = new VueRouter({ ... })

router.beforeEach((to, from, next) => {
  // ...
})
复制代码

当一个导航开始时,全局前置守卫按照注册顺序调用。

守卫是异步链式调用的,导航在最后的一层当中。

new Promise((resolve, reject) => {
    resolve('第一个全局前置守卫')
}.then(() => {
    return '第二个全局前置守卫'
}.then(() => {
    ...
}.then(() => {
    console.log('导航终于开始了') // 导航在最后一层中
})
复制代码

每个守卫方法接收三个参数(往后的守卫都大同小异):

1. to: Route: 即将要进入的目标 路由对象(比如外婆家)

2. from: Route: 当前导航正要离开的路由(比如小明家)

3. next: Function: 一定要调用该方法将控制权交给下一个守卫,执行效果依赖 next 方法的参数。

  • next(): 进入下一个守卫。如果全部守卫执行完了。则导航的状态就是 confirmed (确认的)。

  • next(false): 中断当前的导航(把小明腿打断了)。如果浏览器的 URL 改变了 (可能是用户手动或者浏览器后退按钮),那么 URL 地址会重置到 from 路由对应的地址。

  • next('/') 或者 next({ path: '/' }): 跳转到一个不同的地址。当前的导航被中断,然后进行一个新的导航(小明被打断腿并且送回家了)。你可以向 next 传递任意位置对象,且允许设置诸如 replace: true、name: 'home' 之类的选项以及任何用在 router-link 的 to prop 或 router.push 中的选项。

  • next(error): (2.4.0+) 如果传入 next 的参数是一个 Error 实例,则导航会被终止且该错误会被传递给 router.onError() 注册过的回调。

    永远不要使用两次next,这会产生一些误会。

  • 全局解析守卫

这和 router.beforeEach 类似,但他总是被放在最后一个执行。

  • 全局后置钩子

导航已经确认了的,小明已经到了外婆家了,你打断他的腿他也是在外婆家了。

router.afterEach((to, from) => {
    // 你并不能调用next
  // ...
})
复制代码
  • 路由独享的守卫

在路由内写的守卫

const router = new VueRouter({
  routes: [
    {
      path: '/foo',
      component: Foo,
      beforeEnter: (to, from, next) => {
        // ...
      }
    }
  ]
})
复制代码
  • 组件内的守卫

  1. beforeRouteEnter
  2. beforeRouteUpdate (2.2 新增)
  3. beforeRouteLeave
const Foo = {
  template: `...`,
  beforeRouteEnter (to, from, next) {
    // 路由被 confirm 前调用
    // 组件还未渲染出来,不能获取组件实例 `this`
  },
  beforeRouteUpdate (to, from, next) {
    // 在当前路由改变,但是该组件被复用时调用
    // 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
    // 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
    // 可以访问组件实例 `this`,一般用来数据获取。
  },
  beforeRouteLeave (to, from, next) {
    // 导航离开该组件的对应路由时调用
    // 可以访问组件实例 `this`
  }
}
复制代码
  • 导航全过程

    • 导航被触发。
    • 在准备离开的组件里调用 beforeRouteLeave 守卫。
    • 调用全局的 beforeEach 守卫。
    • 在重用的组件里调用 beforeRouteUpdate 守卫 (2.2+)。(如果你的组件是重用的)
    • 在路由配置里调用 beforeEnter。
    • 解析即将抵达的组件。
    • 在即将抵达的组件里调用 beforeRouteEnter。
    • 调用全局的 beforeResolve 守卫 (2.5+)。
    • 导航被确认。
    • 调用全局的 afterEach 钩子。
    • 触发 DOM 更新。
    • 用创建好的实例调用 beforeRouteEnter 守卫中传给 next 的回调函数。