写点什么

【Vuex 源码学习】第七篇 - Vuex 的模块安装

用户头像
Brave
关注
发布于: 刚刚
【Vuex 源码学习】第七篇 - Vuex 的模块安装

一,前言


上一篇,主要介绍了 Vuex 的模块收集是如何实现的,主要涉及以下几个点:


  • Vuex 模块的概念;

  • Vuex 模块和命名空间的使用;

  • 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 中;


用户头像

Brave

关注

还未添加个人签名 2018.12.13 加入

还未添加个人简介

评论

发布
暂无评论
【Vuex 源码学习】第七篇 - Vuex 的模块安装