首页 > 其他分享 >手撕Vuex-提取模块信息

手撕Vuex-提取模块信息

时间:2024-01-05 11:34:36浏览次数:21  
标签:arr 提取 数组 root account 模块 Vuex children


前言

在上一篇【手撕Vuex-模块化共享数据】文章中,已经了解了模块化,与共享数据的注意点。

那么接下来就要在我们自己的 Nuex 中实现共享数据模块化的功能。那么怎么在我们自己的 Nuex 中实现共享数据模块化的功能呢?

处理数据

也非常的简单,是不是就是处理一下子模块的数据,处理一下子模块的 getters,处理下子模块的 mutations,处理下子模块的 actions 就可以了。

那么怎么处理呢?首先我们来看下数据怎么处理。想要知道怎么处理的,我们首先要知道数据是怎么使用的。

数据怎么使用的,我们在组件当中是不是拿到全局的 Store, 拿到全局的 Store 之后,从全局的 store 中拿到子模块,然后从子模块中拿到数据,然后在组件当中使用。

所以说我需要怎么做,我们需要将子模块的一个数据添加到全局的 Store 当中,好了到这里我们就已经了解了数据怎么处理了。

那么接下来我们就来看下 getters/ mutations/ actions 怎么处理。

处理 getters

处理 getters 首先第一条就是,重名的方法不能不进行覆盖。

处理 mutations

处理 mutations,在 mutations 当中,出现了同名的方法,那么就不能不进行覆盖。

如果说出现了同名的方法,那么取值就是一个数组,将所有的同名方法都添加到这个数组当中。

然后执行这个同名方法就是循环这个数组,然后执行这个数组当中的每一个方法。

处理 actions

处理 actions,如果说出现了同名的方法,那么取值就是一个数组,将所有的同名方法都添加到这个数组当中(同理可证)。

那么知道了怎么处理了之后,接下来怎么办呢?我们就来看下代码怎么写。如果我们直接处理传递进来的数据,可能呢,会比较麻烦,所以说在处理之前呢,我还需要将传递进来的数据进行一下子处理,按照我想要的格式进行格式化一下。

格式化数据

在实现之前,我先将我想格式的数据结构贴出来按照这个结构去编写我们的格式化数据的方法。

let root = {
    _raw: rootModule,
    _state: rootModule.state,
    _children: {
        home: {
            _raw: homeModule,
            _state: homeModule.state,
            _children: {}
        },
        account: {
            _raw: accountModule,
            _state: accountModule.state,
            _children: {
                login: {
                    _raw: loginModule,
                    _state: loginModule.state,
                    _children: {}
                }
            }
        }
    }
}

那么我们就来看下怎么实现这个方法。

由于实现的方法代码比较绕,所以我这里单独开了一个类,来处理这件事情。

这个类的名字叫做 ModuleCollection,这个类的作用就是将传递进来的数据进行格式化,然后返回一个格式化之后的数据。

到这里就要步入正题了,我们就来看下这个类的代码怎么写。

手撕Vuex-提取模块信息_前端

首先在 Store 类当中,将传递进来的数据传递到 ModuleCollection 类当中,然后在 ModuleCollection 类当中,将传递进来的数据进行格式化,然后返回一个格式化之后的数据。

编写 ModuleCollection 类的代码:

class ModuleCollection {
    constructor(options) {
        this.register([], options);
    }

    register(arr, rootModule) {
        
    }
}

首先通过构造函数接收传递进来的数据,然后在构造函数当中,调用 register 方法,将传递进来的数据传递进去。

然后在 register 方法当中,接收两个参数,第一个参数是一个数组,第二个参数是一个对象。

第一个参数是一个数组,这个数组是用来存储模块的名字的,第二个参数是一个对象,这个对象是用来存储模块的数据的。

第一个参数是数组也是我想用来区分是根模块还是子模块的,如果说是根模块,那么这个数组就是空的,如果说是子模块,那么这个数组就是有值的。

好了我们继续走,第一步要处理的就是按照我们需要的格式创建模块,我定义了一个对象 module:

let module = {
    _raw: rootModule,
    _state: rootModule.state,
    _children: {}
}

如上虽然定义了模块信息但是还没有进行存储起来,所以我们的第二步就是保存模块信息。

首先我将根模块进行存储起来,子模块我们稍后再说。

// 2.保存模块信息
if (arr.length === 0) {
    // 保存根模块
    this.root = module;
} else {
    // 保存子模块
}

注意一下我所说的内容,我只是将根模块进行存储起来,子模块还没有进行存储起来。

好,到这里我们的第二部先告一段落,接下来我们就来看下第三步怎么做。

第三步就是处理子模块,我们先来看下怎么处理子模块。

首先我们要知道子模块的名字,这个可以通过循环根模块的 modules 属性来获取。知道了子模块的名称之后,我们就可以通过子模块的名称来获取子模块的数据。从根模块的 modules 属性当中通过子模块的名称来获取子模块的数据。

随后我们就可以通过子模块的数据来创建子模块的模块信息,然后将子模块的模块信息进行存储起来。

我们先将第三步的内容完成,代码如下:

for (let childrenModuleName in rootModule.modules) {
    let childrenModule = rootModule.modules[childrenModuleName];
    this.register(arr.concat(childrenModuleName), childrenModule)
}

如上代码的含义是,首先通过 for in 循环遍历根模块的 modules 属性,然后通过子模块的名称来获取子模块的数据,然后通过子模块的数据来创建子模块的模块信息,然后将子模块的模块信息进行存储起来。

这里就直接递归调用 register 方法,将子模块的名称和子模块的数据传递进去。并且在递归调用的时候,将子模块的名称添加到 arr 数组当中。目的就是为了区分是根模块还是子模块。也是为了方便我们后续的操作(保存子模块)。

好了到这里我们的第三步也完成了,我们先将 arr 数组进行打印,看下 arr 数组的内容是什么。

手撕Vuex-提取模块信息_开发语言_02

❗️注意:记得将官方的 Vuex 注释掉,用我们自己的不然你会发现打印的内容和我们自己的不一样。

打印结果如下图:

手撕Vuex-提取模块信息_前端_03

[] 代表的是根模块,[home] 代表的是 home 模块,[account] 代表的是 account 模块,[account, login] 代表的是 account 模块下的 login 模块。

好了到这里我们的第三步也完成了,接下来我们就来看下之前第二步没有完成的内容怎么完成。

基于第三步的打印结果分析出来各个模块的关系就可以根据这个关系得出各个模块的父子关系。按照这个关系就可以将子模块的模块信息进行存储起来。

我们先来看下代码怎么写,其实非常简单我们先来分析一下,只需要分析 [account, login] 这种情况即可,我还是先将这种场景先不直接就给出答案,我们循序渐进的来,我们就走普通的逻辑,然后再来看下代码怎么写。我会直接往根模块的 children 属性当中添加子模块的模块信息。子模块信息已经通过参数传递进来了,所以说我只需要将子模块的名称获取到即可,根据之前打印的结果来看,子模块的名称是 arr 数组当中的最后一个元素,所以说我只需要获取 arr 数组当中的最后一个元素即可。

然后将子模块的名称作为 key,子模块的模块信息作为 value,添加到根模块的 children 属性当中即可。

代码如下:

this.root._children[arr[arr.length - 1]] = module;

好了到这里我们的第二步也完成了,我们高高兴兴的要去打印结果了,结果如下:

手撕Vuex-提取模块信息_前端_04

发现 login 模块在 root 的 children 属性当中了,login 模块应该在 account 模块的 children 属性当中,所以说我们的代码还是有问题的。

诶,我们的代码有问题,那么我们就来看下问题出在哪里了。

问题出在我们不能直接往根模块的 children 属性当中添加子模块的模块信息,我们应该往父模块的 children 属性当中添加子模块的模块信息。

那么我们怎么知道父模块是谁呢?我们可以通过 root._children 来得到父模块,然后将子模块的模块信息添加到父模块的 children 属性当中即可。

代码如下:

let parent = arr.splice(0, arr.length - 1).reduce((root, currentKey) => {
    return root._children[currentKey];
}, this.root);
parent._children[arr[arr.length - 1]] = module;

让我来逐步解释:

  1. let parent = arr.splice(0, arr.length - 1):这一行代码从数组 arr 中移除并返回除了最后一个元素之外的所有元素,将这些元素存储在 parent 变量中。
  2. .reduce((root, currentKey) => { return root._children[currentKey]; }, this.root):这是一个 reduce 函数调用,它逐个遍历 parent 数组中的元素。root 是累积的结果,初始值是 this.rootcurrentKey 是每次迭代中的当前元素。
  3. parent._children[arr[arr.length - 1]] = module:最后一行代码将 module 赋值给 parent 对象的 _children 属性中的某个属性,该属性的名称来自数组 arr 的最后一个元素。

如上是个简单的解释,接下来我套用数据来解释一下,如下:

例如有这么一个父子结构模块的数组 let testArr = ['account', 'login'];,那么 arr.splice(0, arr.length - 1) 就是将 testArr 数组中的最后一个元素移除并返回除了最后一个元素之外的所有元素,将这些元素存储在 parent 变量中,那么 parent 变量中的值就是 ['account']

然后 reduce 函数调用,它逐个遍历 parent 数组中的元素。root 是累积的结果,初始值是 this.rootcurrentKey 是每次迭代中的当前元素。那么 root._children[currentKey] 就是 this.root._children['account'],那么 this.root._children['account'] 的值就是 account 模块的模块信息。

最后一行代码将 module 赋值给 parent 对象的 _children 属性中的某个属性,该属性的名称来自数组 arr 的最后一个元素。那么 parent._children[arr[arr.length - 1]] 就是 account 模块的模块信息,然后将 module 赋值给 account 模块的子模块,这样我们的 login 模块就在 account 模块的 children 属性当中了。

这个时候我们在来打印一下结果,结果如下:

手撕Vuex-提取模块信息_算法_05

好了这回就是我们想要的结果了,到此为止我们的 ModuleCollection 类就完成了。

标签:arr,提取,数组,root,account,模块,Vuex,children
From: https://blog.51cto.com/u_15652665/9111474

相关文章

  • 手撕Vuex-安装模块数据
    前言根据上一篇,【手写Vuex】-提取模块信息,我们已经可以获取到模块的信息了,将模块信息变成了我们想要的数据结构,接下来我们就要根据模块的信息,来安装模块的数据。在上一篇当中我们定义了一个ModuleCollection类,这个类的作用就是将模块的信息转换成我们想要的数据结构。接下来我们......
  • 手撕Vuex-安装模块方法
    前言经过上一篇文章的介绍,我们实现了将模块安装到store中,那么本章我们就来介绍一下怎么安装模块当中的方法也就是actions、mutations、getters。所以本次文章的目标就是将模块当中的actions、mutations、getters安装到store中,然后在组件中使用。分析阶段那么安装actions、m......
  • 手撕Vue-Router-提取路由信息
    前言好了经过上一篇的学习,我们已经知道了如何监听Hash的变化,如何监听路径的一个变化,本篇我们就可以来实现我们自己的VueRouter了,那么怎么实现呢,在实现之前我们先来回顾一下官方的VueRouter是怎么使用的。VueRouter的使用首先需要去下载官方的VueRouter,如果是通过npm的......
  • stm32实战之su-03t语音模块固件的制作与烧录
    su-03t简介SU-03T是一款低成本、低功耗、小体积的离线语音识别模组,能快速应用于智能家居,各类智能小家电,86盒,玩具,灯具等需要语音操控的产品,SU-03T也具备强大的软件开发能力,我们可以在“智能公元”平台上实现语音固件的零代码开发,提高工作效率。管脚定义其中需要注意的是UART0的B0......
  • 有哪些常用的 Python 模块需要进行安装
    Python是一种高级编程语言,它提供了许多标准库和第三方库,可以帮助我们更快、更高效地编写程序。在Python中,模块是一组相关的函数、类和变量的集合,可以通过导入模块来使用其中的功能。本文将介绍一些常用的Python模块,需要进行安装才能使用。一、NumPyNumPy是一个用于科学计算的Python......
  • 前端歌谣-第四拾九课-node之http模块之fs模块
    前言我是歌谣微信公众号关注前端小歌谣一起学习前端知识今天继续给大家讲解node中fs模块的讲解创建文件constfs=require("fs")fs.mkdir("./geyao",(err)=>{console.log(err)if(err&&err.code==="EEXIST"){console.log("目录已经存在")}})运行结果重命......
  • 前端歌谣-第五十课-node之http模块之fs模块(续)
    前言我是歌谣微信公众号关注前端小歌谣一起学习前端知识今天继续给大家讲解node中fs模块的讲解同步创建constfs=require("fs")fs.mkdirSync("./geyao1",(err)=>{console.log(err)if(err&&err.code==="EEXIST"){console.log("目录已经存在")}})运行......
  • 三菱PLCI模拟量开关量扩展模块钡铼BL200
    随着工业自动化水平的不断提高,对于分布式I/O系统的需求也日益增强。ModbusTCP协议作为一种广泛应用的通讯协议,ModbusTCP协议io模块与三菱PLC结合,实现高效、稳定的分布式I/O系统。ModbusTCP协议是基于以太网传输的Modbus通讯协议,它继承了Modbus协议的优点,同时利用了以太网的高速......
  • C++ Module详解,模块化编程终极指南
    C++Module详解,模块化编程终极指南模块接口文件定义和扩展名模块接口文件定义了模块所提供功能的接口。这些文件通常具有.cppm扩展名。模块接口以声明文件定义了某个名称的模块开始,这被称为模块声明。模块的名称可以是任何有效的C++标识符。名称可以包含点,但不能以点开头或结......
  • 无涯教程-jsoup - 提取属性
    以下示例将HTML解析为Document对象后,使用Elements方法来获取dom元素的属性。Documentdocument=Jsoup.parse(html);Elementlink=document.select("a").first();System.out.println("Href:"+link.attr("href"));元素对象代表dom元素,并提供了各种获取dom元素属性的方法。......