vue-router

212 阅读4分钟

vue的路由钩子是在路由跳转过程中拦截当前路由和要跳转的路由的信息

其中有三种方式可以植入路由导航的过程中:

  1. 全局
  2. 单个路由独享
  3. 组件级的

一、全局钩子

1、全局前置守卫

router.beforeEach 路由改变前的钩子

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

router.beforeEach((to, from, next) => {
  // ...
})

每个守卫的方式接受三个参数:

  • to:将要跳转的路由对象(将要访问的路径)
  • from:代表从哪个路由跳转过来的(当前导航正要离开的路由)
  • next:一定要调用该方法来 resolve 这个钩子。执行效果依赖 next 方法的调用参数

其中next有:

  • next(): 进行管道中的下一个钩子。如果全部钩子执行完了,则导航的状态就是 confirmed (确认的)。
  • next(false): 中断当前的导航。如果浏览器的 URL 改变了 (可能是用户手动或者浏览器后退按钮),那么 URL 地址会重置到 from 路由对应的地址。
  • next('/') 或者 next({ path: '/' }): 跳转到一个不同的地址。当前的导航被中断,然后进行一个新的导航。你可以向 next 传递任意位置对象,且允许设置诸如 replace: true、name: 'home' 之类的选项以及任何用在 router-link 的 to prop 或 router.push 中的选项。
  • next(error): 如果传入 next 的参数是一个 Error 实例,则导航会被终止且该错误会被传递给 router.onError() 注册过的回调。

使用:

  • 使用该函数,一定要调用 next(),否则钩子函数不能 resolve;
  • 该方法比较常用于:验证用户访问权限。

2、全局后置钩子

router.afterEach路由改变后的钩子(也称为全局后置钩子)
router.afterEach((to, from) => {
  // ...
})

该方法同全局前置守卫 router.beforeEach 不同的是少了 next() 函数,也不会改变导航本身。

二、路由独享钩子

baforeEnter对某个路由的单独守卫
const router = new VueRouter({
  routes: [
    {
      path: '/foo',
      component: Foo,
      beforeEnter: (to, from, next) => {
        // ...
      }
    }
  ]
})

使用:

  • 该方法的参数使用同全局前置守卫 router.beforeEach 是一样的;

三、组件内的守卫

baforeRouterEnter(to,from,next)在进入当前组件对应的路由前调用
export default {
    data() { ... },
    beforeRouteEnter(to, from, next) {
        ... ...
    }
}

需要注意的是:

  • 该函数内不能访问当前组件实例 this,因为函数在对应路由被 comfirm 前调用,此时将要渲染的组件实例还没被创建;

  • 可以通过给 next 传递一个回调来访问组件实例,即把组件实例 vm 作为回调方法的参数;该回调的执行在 mounted 后面;

      beforeRouteEnter (to, from, next) {
          next(vm => {
              // 通过 vm 来访问组件实例
          })
      }
    
  • beforeRouteEnter 是支持给 next 传递回调的唯一守卫

beforeRouteUpdate(to, from, next) 在当前路由改变,但是该组件被复用时调用
beforeRouteUpdate (to, from, next) {
    ... ...
}

注意:

  • 该函数内可以访问当前组件实例 this
  • 例如:在一个带有动态参数的路径 /detail/:id,在 /detail/aaa 和 /detail/bbb 之间跳转的时候,因为两个路由渲染的是同个 Detail 组件,因此原来的组件实例会被复用(比起销毁再创建,复用则会更加高效),在这种情况下这个钩子会被调用,而组件的生命周期钩子不会再被调用。
beforeRouteLeave(to, from, next) 在离开当前组件对应的路由前调用
beforeRouteLeave (to, from, next) {
    ... ...
}
  • 该函数内可以访问当前组件实例 this
  • 比如:用户在当前页面有还未保存的内容时突然离开,阻止页面跳转并给出提示,或者在用户离开时清除或存储一些信息等。

四、完整的导航解析流程

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

五、附:使用watch监测路由变化

除了使用钩子函数外,我们也可以使用 watch 来监听 $route 对象,然后根据路由参数的变化来进行响应。

<template>
    <div id=``"app"``>
        <keep-alive>
            <router-view/>
        </keep-alive>
    </div>
</template>

<script>
    export default {
        name: 'App',
        watch: {
            '$route' (to, from) {
                // 对路由变化作出响应...
            }
        }
    }
</script>