Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

vue-router 实现 -- install #23

Open
muwoo opened this issue May 30, 2018 · 4 comments
Open

vue-router 实现 -- install #23

muwoo opened this issue May 30, 2018 · 4 comments

Comments

@muwoo
Copy link
Owner

muwoo commented May 30, 2018

Vue 通过 use 方法,加载VueRouter中的 install 方法。install 完成 Vue 实例对 VueRouter 的挂载过程。下面我们来分析一下具体的执行过程:

export function install (Vue) {
 // ...
  // 混入 beforeCreate 钩子
  Vue.mixin({
    beforeCreate () {
      // 在option上面存在router则代表是根组件 
      if (isDef(this.$options.router)) {
        this._routerRoot = this
        this._router = this.$options.router
        // 执行_router实例的 init 方法
        this._router.init(this)
        // 为 vue 实例定义数据劫持
        Vue.util.defineReactive(this, '_route', this._router.history.current)
      } else {
        // 非根组件则直接从父组件中获取
        this._routerRoot = (this.$parent && this.$parent._routerRoot) || this
      }
      registerInstance(this, this)
    },
    destroyed () {
      registerInstance(this)
    }
  })
 
  // 设置代理,当访问 this.$router 的时候,代理到 this._routerRoot._router
  Object.defineProperty(Vue.prototype, '$router', {
    get () { return this._routerRoot._router }
  })
  // 设置代理,当访问 this.$route 的时候,代理到 this._routerRoot._route
  Object.defineProperty(Vue.prototype, '$route', {
    get () { return this._routerRoot._route }
  })
 
  // 注册 router-view 和 router-link 组件
  Vue.component('RouterView', View)
  Vue.component('RouterLink', Link)

  // Vue钩子合并策略
  const strats = Vue.config.optionMergeStrategies
  // use the same hook merging strategy for route hooks
  strats.beforeRouteEnter = strats.beforeRouteLeave = strats.beforeRouteUpdate = strats.created
  // ...
}

在构造Vue实例的时候,我们会传入router对象:

new Vue({
  router
})

此时的router会被挂载到 Vue 的跟组件this.$options选项中。在 option 上面存在 router 则代表是根组件。如果存在this.$options,则对_routerRoot_router进行赋值操作,之后执行 _router.init() 方法。

为了让 _router 的变化能及时响应页面的更新,所以又接着又调用了 Vue.util.defineReactive方法来进行getset的响应式数据定义。

然后通过 registerInstance(this, this)这个方法来实现对router-view的挂载操作:

 // 执行 vm.$options._parentVnode.data.registerRouteInstance 渲染 router-view 组件
 const registerInstance = (vm, callVal) => {
    let i = vm.$options._parentVnode
    if (isDef(i) && isDef(i = i.data) && isDef(i = i.registerRouteInstance)) {
      i(vm, callVal)
    }
  }

因为只有 router-view 组件定义了data.registerRouteInstance函数。data.registerRouteInstance 主要用来执行 render 的操作,创建 router-view 组件的 Vnode :

data.registerRouteInstance = (vm, val) => {
  // ...
  return h(component, data, children)
}

后续步骤便是为Vue全局实例注册2个属性$router$route;以及组件RouterViewRouterLink

关于Vue.config.optionMergeStrategies 参考 自定义选项合并策略。下一篇我们会接着介绍一下 VueRouter 实例化的过程
有兴趣可以移步vue-router 实现 -- new VueRouter(options)

@Dream4ever
Copy link

多谢分享!最后部分的下一篇文章:vue-router 实现 -- new VueRouter(options),链接给错了,给成了当前这篇文章的链接了~

@byr-gdp
Copy link

byr-gdp commented Jun 1, 2018

为了让 _router 的变化能及时响应页面的更新,所以又接着又调用了 Vue.uti.defineReactive方法来进行get和set的响应式数据定义。

Vue.uti.defineReactive 拼写错了...

@muwoo
Copy link
Owner Author

muwoo commented Jun 1, 2018

@Dream4ever @byr-gdp 谢谢,已更正

@abigmiu
Copy link

abigmiu commented Dec 16, 2022

isDef(i) && isDef(i = i.data) && isDef(i = i.registerRouteInstance) 这一句不理解。 isDef(i = i.data) i = i.data 不是赋值操作嘛。 为啥需要将 i.data 赋值给 i。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants