vue-router--$route和$router以及全局导航守卫

2,823 阅读5分钟

$route和$router

$route是什么

前文提到过,再总结一下,$route是当前活跃的路由对象。

$router是什么

$router是创建出来的路由实例。

他们的由来

他们是vue-router给每个组件添加的两个属性。那vue-router是怎么实现这个功能的呢?

  • 当Vue安装vue-router这个插件的时候(Vue.use(vue-router);),vue-router执行了它的install方法。
  • install方法中,他给Vue这个类,或者说构造函数的原型对象上添加了两个属性:$route$router
    Vue.prototype.$route=...;
    Vue.prototype.$router=根实例的options.Router(之前我们有把导出的路由实例,挂载到根实例上)
  • ** 所有的组件都会继承Vue的原型对象。所以导致所有的组件都会有这两个属性**

全局导航守卫

导航守卫其实可以完全理解成钩子函数。什么意思呢?当路由进行跳转的过程中,跳转前有个钩子,跳转后也有个钩子。就跟beforeCreate函数和created函数一样一样的。而全局导航守卫的意思就是任何路由跳转都会调用这个钩子函数。全局导航守卫是给生成的路由实例部署的。

前置守卫(前置钩子)

beforeEach函数,他是在路由跳转前回调的,它的参数就是一个函数

beforeEach((to,from,next)=>{});

解释一下这三个参数:

  • to 要进入的路由对象。
  • from 将要离开的路由对象。
  • next 这是个方法,意思是跳转的意思。就是执行这个方法,路由就跳转了。所以当你复写beforeEach函数的时候,一定要记得调用next方法。不然路由无法跳转。(本身应该是实现了这个beforeEach函数,但是没有实际的内容只是执行了next方法,当你复写beforeEach函数,就会把本身的benforeEach函数覆盖,那么一定要记得再调用next方法。)

后置守卫(后置钩子)

afterEach函数,他是在路由跳转后回调的,他的参数也是函数。

afterEach((to,from)=>{});
  • to 刚进入的路由对象
  • from 刚离开的路由对象

它不用执行next方法,因为他已经跳转了。

结合导航守卫实现一个小需求

需求

目前,我们实现了三个分页,一个是home页,一个是about页,一个是listing-detail页。当它处于特定页面的时候,html的title应该显示对应的title

实现

router.beforeEach((to,from,next)=>
{
  console.log(to);
  document.title=to.meta.title;
  next();
});

这里要用到一个路由对象的属性叫元数据。我们就把title的值存放在meta中。怎么存放在meta中呢?像params,query我们都是直接传递的,而meta是在配置路由对象的时候直接配置的: 实现效果: 可见有一个很明显的bug。就是开始时应该显示首页但是它显示的是undefined。原因是什么呢?肯定是to对应的那个路由对象有问题,它对应的home路由对象下面的子路由对象。 应该是它! 它并没有配置meta。我们得找它的父路由对象。怎么取得它的父路由对象呢?通过matched属性。match[0]就是它的父路由对象。就算路由对象是独立的,不存在路由嵌套。它的match[0]也是它本身。所以将代码优化一下

router.beforeEach((to,from,next)=>
{
  console.log(to);
  document.title=to.matched[0].meta.title;
  next();
});

拓展:其他导航守卫

导航守卫分为三种:

  • 全局导航守卫(已讲)
  • 路由导航守卫
  • 组件内导航守卫

路由导航守卫

见名知义,这是和路由紧密关联的。所以这个是部署在路由对象的内部的。形式是这样的: 路由导航守卫只有一个:beforeEnter,对应一个函数,也是这三个参数。它在进入该路由前被调用。

组件导航守卫

很显然,这应该和组件对应。应该是定义在组件内部。就很类似组件的生命周期函数。

  • beforeRouteEnter,在该组件对应的路由被进入前,调用。
beforeRouteEnter(to,from,next)
{
}
  • beforeRouteLeave,在该组件对应的路由被离开前,调用。
beforeRouteLeave(to,from,next)
{}

总结

beforeEach,beforeEnter,beforeRouteEnter都是在路由跳转前调用的。而afterEach是在路由离开后调用的,beforeRouteLeave是在路由即将离开的时候调用的。那他们之间的顺序究竟是怎么样的呢?(主要是前三个纠缠不清) 我们以/about路由对象为例。

  • 我添加了全局导航守卫,只要路由被跳转就被调用。
  • 我添加了路由导航守卫,只要进入该路由就被调用
  • 我添加了组件内导航守卫,只要该组件对应的路由进入或离开就被调用 那beforeEach,beforeEnter,beforeRouteEnter执行顺序会是怎么样呢?拭目以待。 我描述一下过程,当我们点击关于的时候:
  1. 路由从"/"跳转到'/about',发生路由的跳转。那么必然触发路由的全局守卫。beforeEach和afterEach。
  2. 对于'/about'路由对象来说,即将进入该路由,那么就会调用beforeEnter函数
  3. 对于about组件来说,即将进入与他对应的路由'/about',就会调用beforeRouteEnter函数。

从结果上来看,执行顺序应该是beforeEach->beforeEnter->beforeRouteEnter->路由跳转->afterEach

注意点

  • 除afterEach外,**其他所有钩子函数都有next方法,一定要记得调用next方法才能进行下一步,不然路由的跳转就在此阻塞!!!!**我猜测应该是内部已经也有这些钩子,没有实际内容但是都执行了next方法,如果你复写,不执行next方法就进行不下去了。路由跳不动!
  • 我发现一个问题,我刚进去的时候,也就是url:localhost:8080它也调用了beforeEach和afterEach方法,出于好奇我还对to/from进行了打印,发现他们的path都是空的:"/"
  • 第三个问题,当我们从"/about"->"/home"的时候,beforeRouteLeave执行顺序比beforeEach早

好了关于路由守卫的探讨就到这里了,有点儿绕,而且可能没有啥实际意义。。。。