一,前言
上一篇,主要介绍了 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 中;
评论