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