前言
请与Vuex | 思路篇 | 第二版模块化 同步阅读
第一阶段:处理模块化--规格化
定义一个类ModuleCollection,构造中默认执行其register方法(递归入口函数)
class ModuleCollection {
constructor(options){
this.register([], options);
}
register(path,rawModule){
let newModule = {
_raw: rawModule, // 当前store对象
_children: {}, // 子模块
state: rawModule.state // 自己模块的状态
}
// 判断是否为最顶层
if(path.length == 0){
this.root = newModule; // 根
}else {
let parent = path.slice(0,-1).reduce((root,current)=>{
return root._children[current];
},this.root);
parent._children[path[path.length-1]] = newModule;
}
if(rawModule.modules){
forEach(rawModule.modules, (childName,module) => {
this.register(path.concat(childName),module)
})
}
}
}
第二阶段:处理模块化的actions、mutations
考虑到以后还有动态注入模块的需求,定义installModule方法,实现注入模块功能
-
输入
- store:用户定义的store对象
- rootState:用户定义的store的state属性
- path:同之前,因为要标识对应父级,所以需要一个path数组进行记录
- rootModule:此store对应的ModuleCollection对象(既规格化好的对象)
-
执行
- 同第一版对getters、mutations、actions的处理,只是改为用数组存储
- 递归rootModule._children 执行 installModule
function installModule(store,rootState,path,rootModule){
if(rootModule._raw.getters){
forEach(rootModule._raw.getters,(getterName,getterFn)=>{
Object.defineProperty(store.getters,getterName,{
get:()=>{
return getterFn(rootModule.state)
}
})
})
}
if(rootModule._raw.actions){
forEach(rootModule._raw.actions,(actionName,actionFn)=>{
let entry = store.actions[actionName] || (store.actions[actionName]=[]);
entry.push(()=>{
actionFn.call(store,store)
})
})
}
if(rootModule._raw.mutations){
forEach(rootModule._raw.mutations,(mutationName,mutationFn)=>{
let entry = store.mutations[mutationName] || (store.mutations[mutationName]=[]);
entry.push(()=>{
mutationFn.call(store,store)
})
})
}
forEach(rootModule._children,(childName,module)=>{
installModule(store,rootState,path.concat(childName),module);
})
}
改写触发逻辑
commit(type){
// console.log(this);
// console.log(this.mutations[type]);
// this.mutations[type]()
this.mutations[type].forEach(mutation=>mutation())
// console.log(this.mutations[type]);
}
dispatch(type){
// this.actions[type]()
this.actions[type].forEach(action=>action())
}
第三阶段:处理模块化的state
if(path.length > 0){
// 先找到对应父模块
let parent = path.slice(0,-1).reduce((root,current)=>{
return root[current];
},rootState)
// 利用此方式实现响应式 将state挂载在parent上
Vue.set(
parent,
path[path.length-1],
rootModule.state
)
}
最终实现
let Vue;
// 默认会被传递Vue的构造
let install = (_vue) => {
console.log(_vue);
Vue = _vue;
// mixin混入 实现每个组件上挂载$store属性
Vue.mixin({
beforeCreate(){
// 判斷是否为根组件
if(this.$options && this.$options.store) {
this.$store = this.$options.store
}else {
this.$store = this.$parent && this.$parent.$store
}
}
})
}
class ModuleCollection {
constructor(options){
this.register([], options);
}
register(path,rawModule){
let newModule = {
_raw: rawModule, // 当前store
_children: {}, // 子模块
state: rawModule.state // 自己模块的状态
}
// 判断是否为最顶层
if(path.length == 0){
this.root = newModule; // 根
}else {
let parent = path.slice(0,-1).reduce((root,current)=>{
return root._children[current];
},this.root);
parent._children[path[path.length-1]] = newModule;
}
if(rawModule.modules){
forEach(rawModule.modules, (childName,module) => {
this.register(path.concat(childName),module)
})
}
}
}
function installModule(store,rootState,path,rootModule){
if(path.length > 0){
// 先找到对应父模块
let parent = path.slice(0,-1).reduce((root,current)=>{
return root[current];
},rootState)
// 利用此方式实现响应式 将state挂载在parent上
Vue.set(
parent,
path[path.length-1],
rootModule.state
)
}
if(rootModule._raw.getters){
forEach(rootModule._raw.getters,(getterName,getterFn)=>{
Object.defineProperty(store.getters,getterName,{
get:()=>{
return getterFn(rootModule.state)
}
})
})
}
if(rootModule._raw.actions){
forEach(rootModule._raw.actions,(actionName,actionFn)=>{
let entry = store.actions[actionName] || (store.actions[actionName]=[]);
entry.push(()=>{
actionFn.call(store,store)
})
})
}
if(rootModule._raw.mutations){
forEach(rootModule._raw.mutations,(mutationName,mutationFn)=>{
let entry = store.mutations[mutationName] || (store.mutations[mutationName]=[]);
entry.push(()=>{
mutationFn.call(store,rootModule.state)
})
})
}
forEach(rootModule._children,(childName,module)=>{
installModule(store,rootState,path.concat(childName),module);
})
}
class Store {
constructor(options){
// this.s = options.state;
let state = options.state;
this.getters = {};
this.mutations = {};
this.actions = {};
const computed = {}
this._vm = new Vue({
data: {
state: state
},
computed
})
this.modules = new ModuleCollection(options);
console.log( this.modules.root);
installModule(this,state,[],this.modules.root);
let {commit,dispatch} = this;
this.commit = (type) => {
commit.call(this,type)
}
this.dispatch = (type) => {
dispatch.call(this,type)
}
}
get state(){
return this._vm.state
}
commit(type){
// console.log(this);
// console.log(this.mutations[type]);
// this.mutations[type]()
this.mutations[type].forEach(mutation=>mutation())
// console.log(this.mutations[type]);
}
dispatch(type){
// this.actions[type]()
this.actions[type].forEach(action=>action())
}
}
function forEach(obj,callback){
Object.keys(obj).forEach(item=>callback(item,obj[item]));
}
export default {
install,Store
}