解析Vue Router源码

Router的从初始化到触发更新时候的流程

如果没有相应的Router源码阅读经历(如React Router的阅读经历),那么可能不需要通过了解整个流程就可以知道大致的实现方式,但是对于没有类似的经历的,那么很难做到窥一斑而知全豹。如果一开始就直接按点来进行讲解的话,那么很多时候都会很懵,因为不知道作用。所以在进行讲解之前,先看一下Vue Router的工作流程。

初始化

在项目初始化的时候,会先进行VueRouter的安装,只需要记住安装的时候会在Vue中混入了一个生命周期钩子函数,将根组件的_route响应式化(后面会用到)。

接下来就是路由的初始化,通过将配置项进行解析,执行以下流程。

上面的流程中,要注意以下几点:

  • Matcher进行初始化的时候,会将路由表制作成路由映射,后面调用router的切换路由的方法的时候,会从这里拿到相应的路由配置。
  • History进行初始化的时候,会进行根据不同的类型路由来进行不同的事件的注册,如果是hash或者h5类型的话,会在浏览器上注册事件。回调事件也是进行更新路由视图的起点。
  • beforeCreate的生命周期钩子函数中,只在路由对应的根组件中提添加_route响应式属性,在其他的组件没有,只能进行代理访问。
  • router-view组件中进行注册_route回调的前提是在render函数中引用到,这个要得了解什么响应数据的依赖的添加的时机才能够明白。

更新路由

首先要明白路由更新的起点在哪?根据不同类型的路由分类如下:

路由类型 更新起点
Hash popState、pushState、hashChange、replaceState、go、push、replace
H5 popState、pushState、replaceState、go、push、replace
Abstract go、push、replace

具体的流程图如下:

VuexVue Router很骚的一点就是它会去适当使用Vue的数据响应系统来进行事件通知功能,这是很巧妙的设计(不用关心Vue的版本,是使用Object.defineProperty还是代理来实现的),同时也是其强耦合度的体现。

入口

install.js文件中,对路由、路由组件、路由混入事件、路由响应式对象创建的操作等进行了执行。下面会进行解释作用。

function install (Vue) {
   
  if (install.installed && _Vue === Vue) return
  install.installed = true

  _Vue = Vue

  const isDef = v => v !== undefined

  // 进行注册router实例
  const registerInstance = (vm, callVal) => {
   
    let i = vm.$options._parentVnode
    // 在data之后进行初始化
    if (isDef(i) && isDef(i = i.data) && isDef(i = i.registerRouteInstance)) {
   
      i(vm, callVal)
    }
  }

  Vue.mixin({
   
    beforeCreate () {
   
      // 在beforeCreate执行环境的时候,this指向的是新创建出来的vm实例
      if (isDef(this.$options.router)) {
   
        // 如果配置项有router选项的时候,那么这个vm实例就是router的根组件
        this._routerRoot = this
        this._router = this.$options.router
        this._router.init(this)
        // 定义响应数据。在router-view组件(后面会说)中的渲染函数中会访问到这个属性,同时会添加上依赖。当修改到本数据的时候,会触发数据相应系统,重新渲染对应的router-view。更改视图层
        Vue.util.defineReactive(this, '_route', this._router.history.current)
      } else {
   
        // 如果不是路由根目录组件的时候,那么就会将_routerRoot属性赋值为根目录组件
        this._routerRoot = (this.$parent && this.$parent._routerRoot) || this
      }
      // 进行注册路由操作
      registerInstance(this, this)
    },
    destroyed () {
   
      // 进行移除操作
      registerInstance(this)
    }
  })

  // 下面两个方法都是代理操作
  Object.defineProperty(Vue.prototype, '$router', {
   
    get () {
    return this._routerRoot._router }
  })

  Object.defineProperty(Vue.prototype, '$route', {
   
    get () {
    return this._routerRoot._route }
  })

  Vue.component('RouterView', View)
  Vue.component('RouterLink', Link)

  const strats = Vue.config.optionMergeStrategies
  // use the same hook merging strategy for route hooks
  strats.beforeRouteEnter = strats.beforeRouteLeave = strats.beforeRouteUpdate = strats.created
}

在安装文件干了三件事:

  • 混入钩子函数,进行路由注册,并且进行定义响应式数据,方便后面路由改变的时候通知视图层进行更新

  • 进行代理操作,实例访问$router或者$route属性的时候会代理到跟组件的_route属性中(所以其实在对$route进行观察的时候,实际上是对根目录的_route属性进行观察,而这个属性已经变成了响应型数据,所以路由改变的时候能够实现回调观察的作用)一张图来说明引用的整个流程:

  • 注册全局组件。

Router的组成

1.VueRouter实例

VueRouter类是对外的接口,用户通过创建实例来进行路由控制,VueRouter类是对路由配置以及钩子函数进行管理、对内部功

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值