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