VueRouter源码之实现install方法

101 阅读1分钟

下文记录了,自己第一天学习VueRouter的源码。VueRouter的源码有很多个组成部分,很大块,只能一天天的啃了,一下子肯定干不完。我的感受就是,短短的几行代码,但是里面的逻辑都很深。秋招加油叭!后面还会更新,如果有错误,请指正,轻喷!

// 原本的vue-router是怎么写的

// Vue注册使用VueRouter
Vue.use(VueRouter)
// 创建一个VueRouter实例
const router = new VueRouter({
  routes: [
    {
      path: '/shouye',
      component: homeComponent,
    },
  ],
})
// 创建vue实例 注册router对象
new Vue({
  router,
  render: (h) => h(App),
}).$mount('#app')

// 模拟VueRouter部分
// 1. 声明一个全局变量_vue
//    为什么要声明要给全局变量_vue?
//    因为我们要在很多地方使用vue的构造函数,比如Vue.component来创建组件 -》生成 router-link 和 router-view组件
let _vue = null

// 2. 导出一个类
//    为什么要导出一个类
//    因为 new VueRouter()实例 就是把VueRouter当作一个构造函数或者是类来看待
export default class VueRouter {
  // 3. 写install方法是为了什么?
  // 这里对应Vue.use(VueRouter) Vue.use() 里面会接受一个“对象”或者“方法” 如果是方法 会直接调用 如果是对象 会调用这个对象里面的install方法 => 意味着如果是对象实例,里面必须有install方法 Vue才能够注册
  // 调用的时候会传递 Vue构造函数
  static install(Vue) {
    // 4. 下面 为了判断 插件是否已经被安装,我们“手动”给VueRouter的install方法配上 install属性,方法也是对象 也可以配上属性,如果已经install了,就不需要再次install了,直接return
    //    如果没有 我们才会去执行下面
    if (VueRouter.install.installed) {
      return
    }
    // 我们给这个属性 给为true 下次不会重复安装。
    VueRouter.install.installed = true

    // 给_vue全局变量 赋值 Vue这个构造函数
    _vue = Vue

    // 5. 这一步是混入,为什么考虑到用混入?
    //    1. 因为我们想要进行下面这段代码,给Vue全局的构造函数的prototype原型对象挂载$router,这样挂载以后 在vue的任何实例、组件都可以使用this.$router.push this.$router.back……
    //    2. 但是我们注意到 this这里指的是VueRouter 为什么? 因为是VueRouter.install()方法调用,
    //    3. 所以我们考虑用Vue.mixin()方法 在Vue的构造函数里面的方法使用this,this就会指向Vue的构造函数
    //    4. 为什么this要指向Vue构造函数的实例,因为 new Vue({router}) 里面的{router}是传递给 new Vue实例的,确切的来说指向的是每个vue实例
    //  _vue.prototype.$router = this.$options.router
    _vue.mixin({
      // 6. 我们希望每次都是new Vue实例的时候才挂载路由,new VueRouter实例而不是每次组件已创建,都会执行一遍,怎么操作呢?
      // 1. 怎么判断是 new Vue 实例还是组件创建呢?
      //    我们通过 beforeCreate()钩子函数,这个函数里面vue的实例已经创建好了 可以获取的到实例
      //    我们判断是否有this.$options.router
      //    就是看 new Vue({router}) 这个里面是否传递了router实例 如果传递了 就挂载到_vue.prototype.$router上面去
      beforeCreate() {
        if (this.$options.router) {
          _vue.prototype.$router = this.$options.router
        }
      },
    })
  }
}