Vuex的原理 (一、Vue.use(vuex)做了什么?)

Vuex的原理 一

  针对vuex的版本 3.5.1
  • Vue.use(vuex)这个过程中vuex都做了什么?

调用vuex的install方法,判断Vuex是否已经注册过了,注册过了就直接返回,这里使用的是单例模式。
调用applyMixin(Vue)
将初始化vuex的方法(vuexInit)混入到vue的beforeCreate生命周期中;
将$store绑定到每个vue实例中。

源码解读
  • 再看install方法之前,我们需要先了解一下vuex.use方法都做了什么,源码位置位于Vue源码项目中的 src/global-api/use.js

      Vue.use = function (plugin: Function | Object) {
          const installedPlugins = (this._installedPlugins || (this._installedPlugins = []))
          if (installedPlugins.indexOf(plugin) > -1) { // Vue检测是否已经注册过这个插件, 如果已经注册过就直接返回
            return this
          }
    
          // additional parameters
          const args = toArray(arguments, 1) // 把参数截取出来组成一个数组,后面需要作为apply的第二个参数传入,注意这里不要第一个参数,因为第一个参数是我们的插件,比如(vuex,vueRouter、elementui)等;
          args.unshift(this) // 把Vue作为第一个参数
          if (typeof plugin.install === 'function') {
            plugin.install.apply(plugin, args) // 如果插件有intall方法就直接调用他的install方法,并把args传入。
          } else if (typeof plugin === 'function') {
            plugin.apply(null, args)
          }
          installedPlugins.push(plugin)
          return this
        }
    
    • 接下来我们看Vuex的install方法,源码位置在Vuex的 src/store.js
      export function install (_Vue) {
        if (Vue && _Vue === Vue) { // 这里也是判断Vue是否已经注册过vuex了,如果注册过就直接返回,注意vuex是单例模式
          if (__DEV__) {
            console.error(
              '[vuex] already installed. Vue.use(Vuex) should be called only once.'
            )
          }
          return
        }
        Vue = _Vue
        applyMixin(Vue) // 调用applyMixin, 看下这个函数干了啥
      }
    
    • applyMixin 方法 源码位于 Vue的 src/mixin.js
     export default function (Vue) {
       const version = Number(Vue.version.split('.')[0]) // 获取vue的版本
    
       if (version >= 2) { // 如果版本大于等于2, 就在vue的beforeCreate中混入vuexInit函数, 接下来看一下vuexInit
         Vue.mixin({ beforeCreate: vuexInit })
       } else { // 这段代码可以不看, 针对vue低版本的vuex的处理
         // override init and inject vuex init procedure
         // for 1.x backwards compatibility.
         const _init = Vue.prototype._init
         Vue.prototype._init = function (options = {}) {
           options.init = options.init
             ? [vuexInit].concat(options.init)
             : vuexInit
           _init.call(this, options)
         }
       }
    
       /**
        * Vuex init hook, injected into each instances init hooks list.
        */
    
       function vuexInit () { // 当我们实例化vue的时候就会调用这个函数了。
         const options = this.$options // 获取vue的$options
         // store injection
         if (options.store) { // 判断options中是否存在store属性,这里就是我们在vue的main.js中实例化Vue时写的new Vue({store}).$mount('app')
           this.$store = typeof options.store === 'function'
             ? options.store()
             : options.store  // 将vuex绑定到Vue实例的$store属性上
         } else if (options.parent && options.parent.$store) { 
           /* 这里的代码的意思是,我们需要在任何Vue的组件中都能通过使用this.$store直接调用vuex,
           所以vuex给我们做了这个工作,如果当前组件的option没有store属性,
           就看他的父组件上有没有,直到拿到store,然后赋值给$store属性,
           这样我们就能在Vue的组件中使用this.$store了。*/
           this.$store = options.parent.$store
         }
       }
    

    总结 Vue.use(vuex)

       - 判断vue是否已经注册过vuex插件;
       - 将`vuexInit`函数混入到vue的beforeCreate生命周期中;
       - 实例化vue时,会在vue每个实例上添加$store属性,并将vuex的实例绑定到$store属性上。
    

个人github地址 https://github.com/ComponentTY/vue-sourcecode/tree/master/vuex

posted @ 2021-01-08 16:13  骑着蜗牛看落日  阅读(2750)  评论(0编辑  收藏  举报