Vue Router

286 阅读3分钟

官方传送门

1.编程式的导航

router.push(location, onComplete?, onAbort?)

向history栈中添加一个记录,点击回退可回到之前的url

Vue实例内部,可以通过 $router 访问路由实例。因此可以调用 this.$router.push

用法

声明式 编程式
<router-link :to="..."> router.push(...)
// 字符串
router.push('home')

// 对象
router.push({ path: 'home' })

// 命名的路由
router.push({ name: 'user', params: { userId: '123' }})

// 带查询参数,变成 /register?plan=private 
router.push({ path: 'register', query: { plan: 'private' }})

注意点:

问题1:使用 pathparams进行传递参数 将导致无效,

// 这里的 params 不生效
router.push({ path: '/user', params: { userId }}) // -> /user

解决方案1:

你需要提供路由的 name 或手写完整的带有参数的 path:

const userId = '123'
router.push({ name: 'user', params: { userId }}) // -> /user/123
router.push({ path: `/user/${userId}` }) // -> /user/123

问题2:路由地址只有参数变化将不会响应变化

如果目的地和当前路由相同,只有参数发生了改变,数据将不会得到更新 (比如从一个用户资料到另一个 /users/1 -> /users/2)

原因:两个路由都渲染同个组件,比起销毁再创建,复用则显得更加高效。不过,这也意味着组件的生命周期钩子不会再被调用。

解决方案2:

1.需要使用 beforeRouteUpdate 来响应这个变化

const User = {
  template: '...',
  beforeRouteUpdate (to, from, next) {
    // react to route changes...
    // don't forget to call next()
  }
}

2.使用watch对路由$route对象进行监听

const User = {
  template: '...',
  watch: {
    '$route' (to, from) {
      // 对路由变化作出响应...
    }
  }
}

导航守卫

全局前置守卫

发生时间:守卫是异步解析执行,此时导航在所有守卫 resolve 完之前一直处于等待中

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

next()必须调用,否则无法钩子函数不会进入resolved

全局解析守卫(2.5.0新增)

发生时间:在导航被确认之前,同时在所有组件内守卫和异步路由组件被解析之后,解析守卫就被调用。

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

全局后置钩子

不会接受next函数也不会改变导航本身

router.afterEach((to,from)=>{.....})

路由独享守卫

在路由配置中直接定义

const router = new VueRouter({
  routes: [
    {
      path: '/foo',
      component: Foo,
      beforeEnter: (to, from, next) => {
        // ...
      }
    }
  ]
})

组件内的守卫

  • beforeRouteEnter
  • beforeRouteUpdate (2.2 新增)
  • beforeRouteLeave
const Foo = {
  template: `...`,
  beforeRouteEnter (to, from, next) {
    // 在渲染该组件的对应路由被 confirm 前调用
    // 不!能!获取组件实例 `this`
    // 因为当守卫执行前,组件实例还没被创建
    // 不过可以传一个回调给next来访问组件实例,如下
    next(vm=>{
        // 通过 `vm` 访问组件实例
    })
  },
  beforeRouteUpdate (to, from, next) {
    // 在当前路由改变,但是该组件被复用时调用
    // 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
    // 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
    // 可以访问组件实例 `this`
    this.name = to.params.name
    next()
  },
  beforeRouteLeave (to, from, next) {
    // 导航离开该组件的对应路由时调用
    // 可以访问组件实例 `this`
  }
}

这个离开守卫通常用来禁止用户在还未保存修改前突然离开。该导航可以通过 next(false) 来取消。

beforeRouteLeave (to, from , next) {
  const answer = window.confirm('Do you really want to leave? you have unsaved changes!')
  if (answer) {
    next()
  } else {
    next(false)
  }
}

完整的导航解析流程

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