一,前言
上一篇,主要介绍了 Vuex 的模块收集是如何实现的,主要涉及以下几个点:
本篇,继续介绍 Vuex 中模块安装的实现;
二,前文梳理
最外层的 index 模块,即 Vuex 的根模块;
在 Vuex 的根模块中,包含两个子模块:模块 a 和模块 b;
模块 a 中又包含子模块 c,这样就构建了一个树形结构;
所以,Vuex 模块,理论上是一棵支持无限层级的模块树;
依赖收集的过程,就是将 Vuex 的模块关系进行格式化,具体到代码中的体现就是递归;
通过 ModuleCollection
类对 Vuex 模块递归地进行格式化处理,以便于 Vuex 对状态进行操作;
(可以了解下做组合模式,用于处理树型结构)
通过 register(path, rootModule)
进行模块注册:
path
数组类型,当前待注册模块的完整路径;
rootModule
当前待注册模块对象;
这样,就知道了各个模块间的层级关系,从而递归构建出一棵模块树;
下一步,根据格式化后的模块树,进行 Vuex 的模块安装;
三,模块安装
模块收集:是将模块对象格式化为“模块树”;
模块安装:递归“模块树”,并将所有模块中的 getter、mutation、action 全部定义到当前 Store 中;
1,模块安装的逻辑
在 Store 类中,创建模块安装方法 installModule 对当前模块对象进行递归处理;
从根模块开始,将 getter、mutation、action 都放到 Store 中,即 this._actions、this._mutations、this._wrappedGetters 中;
备注:对象不便于方法和能力的扩展,考虑重构为 Module 类,对相关操作进行封装和调用;
2,优化:将模块对象重构为 Module 类
创建 Module 类:src/vuex/modules/module.js
class Module {
constructor(newModule) {
this._raw = newModule;
this._children = {};
this.state = newModule.state
}
getChild(key) {
return this._children[key];
}
addChild(key, module) {
this._children[key] = module
}
// 基于 Module 类,为模块扩展其他能力...
forEachMutation(fn) {
if (this._raw.mutations) {
Object.keys(this._raw.mutations).forEach(key=>fn(this._raw.mutations[key],key));
}
}
forEachAction(fn) {
if (this._raw.actions) {
Object.keys(this._raw.actions).forEach(key=>fn(this._raw.actions[key],key));
}
}
forEachGetter(fn) {
if (this._raw.getters) {
Object.keys(this._raw.getters).forEach(key=>fn(this._raw.getters[key],key));
}
}
forEachChild(fn) {
Object.keys(this._children).forEach(key=>fn(this._children[key],key));
}
}
export default Module;
复制代码
修改
import Module from "./module";
class ModuleCollection {
constructor(options) {
this.register([], options);
}
register(path, rootModule) {
// 格式化:构建 Module 对象
// 通过类的方式产生实例,便于后续的扩展
let newModule = new Module(rootModule);
// let newModule = {
// _raw: rootModule, // 当前模块的完整对象
// _children: {}, // 当前模块的子模块
// state: rootModule.state // 当前模块的状态
// }
if (path.length == 0) {
this.root = newModule;
} else {
let parent = path.slice(0, -1).reduce((memo, current) => {
// 此时 memo 为 Module 类,使用 getChild 方法进行处理;
return memo.getChild(current);
// return memo._children[current];
}, this.root)
// 此时 memo 为 Module 类,使用 addChild 方法进行处理;
parent.addChild(path[path.length - 1], newModule);
// parent._children[path[path.length - 1]] = newModule
}
if (rootModule.modules) {
Object.keys(rootModule.modules).forEach(moduleName => {
let module = rootModule.modules[moduleName];
this.register(path.concat(moduleName), module)
});
}
}
}
export default ModuleCollection;
复制代码
测试结果:
功能正常,仅将模块重构为 Module 类,便于后续的功能扩展
3,模块安装的实现
在 src/vuex/store.js 中,创建 installModule 方法,用于 Vuex 的模块安装操作:
/**
* 安装模块
* @param {*} store 容器
* @param {*} rootState 根状态
* @param {*} path 所有路径
* @param {*} module 格式化后的模块对象
*/
const installModule = (store, rootState, path, module) => {
// 遍历当前模块中的 actions、mutations、getters
// 将它们分别定义到 store 中的 _actions、_mutations、_wrappedGetters;
// 遍历 mutation
module.forEachMutation((mutation, key) => {
// 处理成为数组类型:每个 key 可能会存在多个需要被处理的函数
store._mutations[key] = (store._mutations[key] || []);
// 向 _mutations 对应 key 的数组中,放入对应的处理函数
store._mutations[key].push((payload) => {
// 执行 mutation,传入当前模块的 state 状态
mutation.call(store, module.state, payload);
})
})
// 遍历 action
module.forEachAction((action, key) => {
store._actions[key] = (store._actions[key] || []);
store._actions[key].push((payload) => {
action.call(store, store, payload);
})
})
// 遍历 getter
module.forEachGetter((getter, key) => {
// 注意:getter 重名将会被覆盖
store._wrappedGetters[key] = function () {
// 执行对应的 getter 方法,传入当前模块的 state 状态,返回执行结果
return getter(module.state)
}
})
// 遍历当前模块的儿子
module.forEachChild((child, key) => {
// 递归安装/加载子模块
installModule(store, rootState, path.concat(key), child);
})
}
复制代码
至此,“模块树”中全部的 actions、mutations、getters 都放入了 store 中的 _actions、_mutations、_wrappedGetters 中;
评论