当前位置: 首页 > article >正文

手写vuex4源码(四)模块的状态的实现

一、模块收集

1、模块的树形结构-模型树

Vuex 的模块,理论上是支持无限层级递归的树型结构;

但当前版本的 Vuex 仅仅处理了单层 options 对象;

因此,需要继续添加支持深层处理的递归逻辑,从而完成“模块树”的构建,即:实现 Vuex 的模块收集;

为了能够模拟出多层级的“模块树”,我们再创建一个模块 ModuleC,并注册到 ModuleA 下;

模块层级设计:index 根模块中包含模块 A、模块 B;模块 A 中,又包含了模块 C;

modules: { // 子模块
    aCount: {
      namespaced: true,
      state: { count: 0 },
      mutations: {
        add(state, payload) { // aCount/add
          state.count += payload
        }
      },
      modules: {
          cCount: {
              namespaced:true,
              state: { count: 0 },
              mutations: {
                  add(state, payload) { // aCount/cCount
                      state.count += payload
                  }
              },
          }
      }
    },
    bCount: {
      state: { count: 0 },
      namespaced: true,
      mutations: {
        add(state, payload) {
          state.count += payload
        }
      },
    }
  }

2、模块收集的逻辑

我们期望最后实现的结构如下

{
  _raw: '根模块',
  _children:{
    moduleA:{
      _raw:"模块A",
      _children:{
        moduleC:{
          _raw:"模块C",
          _children:{},
          state:'模块C的状态'  
        }
    	},
    	state:'模块A的状态'  
    },
    moduleB:{
      _raw:"模块B",
      _children:{},
      state:'模块B的状态'  
    }
  },
  state:'根模块的状态'
}

3、模块收集的实现

在vuex下创建Modules文件夹,创建module-collection.js文件,创建 ModuleCollection 类:用于在 Vuex 初始化时进行模块收集操作;

export default class ModuleCollection {}

模块收集的操作,就是(深度优先)递归地处理 options 选项中的 modules 模块,构建成为树型结构:

创建 register 方法:携带模块路径,对当前模块进行注册,执行“模块树”对象的构建逻辑;

register(rawModule, path) {
        const newModule = new Module(rawModule);
        // rawModule.newModule = newModule; // 把新的模块 添加到原始对象上
        if (path.length == 0) { // 是一个根模块
            this.root = newModule
        } else {
            const parent = path.slice(0, -1).reduce((module, current) => {
                return module.getChild(current)
            }, this.root);
            parent.addChild(path[path.length - 1], newModule)
        }
        if (rawModule.modules) {
            forEachValue(rawModule.modules, (rawChildModule, key) => {
                this.register(rawChildModule, path.concat(key))
            })
        }
        console.log(newModule)
        return newModule
    }

在这里插入图片描述

模块安装

递归当前树中的state、getter、mutation、action 定义到当前 store 实例中
在 Store 类中,创建 installModule 模块安装方法:对当前模块对象进行递归处理;
Module 类:src/vuex/modules/module.js

// src/vuex/modules/module.js

/**
 * Module 模块类,提供模块数据结构与相关能力扩展
 */
class Module {
  constructor(newModule) {
    this._raw = newModule;
    this._children = {};
    this.state = newModule.state
  }
  /**
   * 根据模块名获取模块实例
   * @param {*} key 模块名
   * @returns 模块实例
   */
  getChild(key) {
    return this._children[key];
  }
  /**
   * 向当前模块实例添加子模块
   * @param {*} key     模块名
   * @param {*} module  子模块实例
   */
  addChild(key, module) {
    this._children[key] = module
  }

  // 基于 Module 类,为模块扩展其他能力...

  /**
   * 遍历当前模块下的 mutations,具体处理由外部回调实现
   * @param {*} fn 返回当前 mutation 和 key,具体处理逻辑由调用方实现
   */
  forEachMutation(fn) {
    if (this._raw.mutations) {
      Object.keys(this._raw.mutations).forEach(key=>fn(this._raw.mutations[key],key));
    }
  }
  /**
   * 遍历当前模块下的 actions,具体处理由外部回调实现
   * @param {*} fn 返回当前 action 和 key,具体处理逻辑由调用方实现
   */
  forEachAction(fn) {
    if (this._raw.actions) {
      Object.keys(this._raw.actions).forEach(key=>fn(this._raw.actions[key],key));
    }
  }
  /**
   * 遍历当前模块下的 getters,具体处理由外部回调实现
   * @param {*} fn 返回当前 getter 和 key,具体处理逻辑由调用方实现
   */
  forEachGetter(fn) {
    if (this._raw.getters) {
      Object.keys(this._raw.getters).forEach(key=>fn(this._raw.getters[key],key));
    }
  }
  /**
   * 遍历当前模块的子模块,具体处理由外部回调实现
   * @param {*} fn 返回当前子模块 和 key,具体处理逻辑由调用方实现
   */
  forEachChild(fn) {
    Object.keys(this._children).forEach(key=>fn(this._children[key],key));
  }
}

export default Module;

组合state,通过path.slice(0, -1).reduce的方法,组装父子树

// 定义状态
        const state = store._modules.root.state; // 根状态
        installModule(store, state, [], store._modules.root);

function installModule(store, rootState, path, module) { // 递归安装
    let isRoot = !path.length; // 如果数组是空数组 说明是根,否则不是

    if (!isRoot) { // []
        let parentState = path.slice(0, -1).reduce((state, key) => state[key], rootState);
        store._withCommit(() => {
            parentState[path[path.length - 1]] = module.state;
        })
    }
        module.forEachChild((child, key) => { // aCount,bCount
        installModule(store, rootState, path.concat(key), child);
    })
}

http://www.kler.cn/a/5480.html

相关文章:

  • Pyspark_结构化流2
  • 数据的存储--->【大小端字节序】(Big Endian)(Little Endian)
  • Python —— 给女儿写个雷霆战机
  • 命令行上的数据科学第二版:十、多语言数据科学
  • Leetcode.1849 将字符串拆分为递减的连续值
  • 第二十八章 变换坐标总结
  • C++模板基础(四)
  • 有了Bug,先看看类型
  • Activation Function激活函数
  • 三极管用作开关电路的一些思考
  • 跟着AI学AI(1): 线性回归模型
  • 如何使用Spring+OpenAI生成图像
  • 多传感器融合定位GNSS、IMU、Lidar、Camera
  • 06 Laplacian算法
  • HTML5 SSE
  • 数据结构和算法(3):递归
  • 程序员万万不能去的3种公司,越做越倒退,过来人的经验
  • VerilogHDL基本语法和程序
  • PCB模块化设计24——DCDC电源模块PCB布局布线设计规范
  • python Format()函数的用法___实例详解(一)(全,例多)___各种格式化替换,format对齐打印