Vuex源码分析(一)-- 插件注册
先说总结:
Vue.use(Vuex)
,会给当前Vue组件的beforeCreate
生命周期添加一个方法,这个方法会将在根节点引入的store
对象,传入所有的子节点中- 这个
store
对象是通过new Vuex.Store({})
生成的;也可以是一个方法,用以返回Store
对象 - 然后通过
new Vue({store})
在根节点引入
然后看一下Vuex
对象的属性结构
export {
Store, // sotre对象,用于构造store实例,new Store()
install, // Vue.use(Vuex) 注册所需的方法
mapState, // 将 state 按一定方式展开为 map 结构的对象
mapMutations, // 将 mutations 按一定方式展开为 map 结构的对象
mapGetters, // 将 getters 按一定方式展开为 map 结构的对象
mapActions, // 将 actions 按一定方式展开为 map 结构的对象
// 重新指定命名空间,返回对应的 {mapState,mapMutations,mapGetters,mapActions} 方法
createNamespacedHelpers,
createLogger // 内置 Logger 插件,开发调试时使用
}
Vuex
插件注册的方式为 Vue.use(Vuex)
,所以只看Vuex.install
方法
let Vue
export function install (_Vue) {
// 同一个Vue 只能通过 Vue.use(Vuex) 注册一次
if (Vue && _Vue === Vue) {
return
}
Vue = _Vue
applyMixin(Vue)
}
接下来是applyMixin(Vue)
方法,这段代码也好理解,针对不同版本做兼容处理。
2.0
以上版本进行混淆Vue.mixin({ beforeCreate: vuexInit })
。由于Vue.use(Vuex)
是在一开始就调用的,所以这个方法会在beforeCreate
生命周期第一个执行2.0
以下版本,在options.init
的第一个数组位置加上vuexInit
方法
export default function (Vue) {
const version = Number(Vue.version.split('.')[0])
if (version >= 2) {
Vue.mixin({ beforeCreate: vuexInit })
} else {
const _init = Vue.prototype._init
Vue.prototype._init = function (options = {}) {
options.init = options.init ? [vuexInit].concat(options.init) : vuexInit
_init.call(this, options)
}
}
}
接下来是vuexInit
方法
function vuexInit () {
const options = this.$options
// this.$options.store存在,表明当前Vue实例传入了store,即 new Vue({store})
if (options.store) {
// 这里表明,传入的store既可以是一个方法,也可以是一个对象
this.$store = typeof options.store === 'function' ? options.store() : options.store
} else if (options.parent && options.parent.$store) {
// 如果当前 $options 没有 store,取父组件的 store
// 这就保证了在根节点引入的 store 会传入所有子节点
this.$store = options.parent.$store
}
}