vuex插件
有了上文作为铺垫,我们就可以很轻松的来解释vuex的原理了。
Vuex仅仅是Vue的一个插件。Vuex只能使用在vue上,因为其高度依赖于Vue的双向绑定和插件系统。
Vuex的注入代码比较简单,调用了一下applyMixin方法,现在的版本其实就是调用了Vue.mixin,在所有组件的 beforeCreate生命周期注入了设置 this.$store这样一个对象。
// src/store.jsexport function install (_Vue) {if (Vue && _Vue === Vue) {return}Vue = _VueapplyMixin(Vue)}// src/mixins.jsexport default function (Vue) {const version = Number(Vue.version.split('.')[0])if (version >= 2) {Vue.mixin({ beforeCreate: vuexInit })} else {const _init = Vue.prototype._initVue.prototype._init = function (options = {}) {options.init = options.init? [vuexInit].concat(options.init): vuexInit_init.call(this, options)}}function vuexInit () {const options = this.$options// store injectionif (options.store) {this.$store = typeof options.store === 'function'? options.store(): options.store} else if (options.parent && options.parent.$store) {this.$store = options.parent.$store}}}
划重点:1行代码 Vue.mixin
那么 Vuex.Store 是如何实现的呢?
// src/store.jsconstructor (options = {}) {const {plugins = [],strict = false} = options// store internal statethis._committing = falsethis._actions = Object.create(null)this._actionSubscribers = []this._mutations = Object.create(null)this._wrappedGetters = Object.create(null)this._modules = new ModuleCollection(options)this._modulesNamespaceMap = Object.create(null)this._subscribers = []this._watcherVM = new Vue()const store = thisconst { dispatch, commit } = thisthis.dispatch = function boundDispatch (type, payload) {return dispatch.call(store, type, payload)}this.commit = function boundCommit (type, payload, options) {return commit.call(store, type, payload, options)}// strict modethis.strict = strictconst state = this._modules.root.state// init root module.// this also recursively registers all sub-modules// and collects all module getters inside this._wrappedGettersinstallModule(this, state, [], this._modules.root)resetStoreVM(this, state)// apply pluginsplugins.forEach(plugin => plugin(this))}
划重点:其实上面的代码绝大部分都不需要关注的 - -。
其实重点就是一行代码 resetStoreVM(this, state)。
那么 resetStoreVM 里面是什么呢?
// src/store.jsfunction resetStoreVM (store, state, hot) {Vue.config.silent = truestore._vm = new Vue({data: {$$state: state},computed})}
划重点: 还是一行代码:new Vue。通过 Vue自己的双向绑定然后注入
你是不是以为就这样结束了呢? NoNoNo,当你再Vue中通过this如果调用store的数据呢?
// 当获取state时,返回以双向绑定的$$satevar prototypeAccessors$1 = { state: { configurable: true } };prototypeAccessors$1.state.get = function () {return this._vm._data.$$state};// 将state定义在原型中Object.defineProperties( Store.prototype, prototypeAccessors$1 );
其实就是获取 this._vm._data.$$state 而已
总结
Vue的双向绑定通过调用new Vue实现,然后通过Vue.mixin注入到Vue的生命周期中,再通过劫持state.get将数据放入组件中。
