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

【手写 Vuex 源码】第十篇 - Vuex 命名空间的实现

一,前言

上一篇,主要介绍了 Vuex 响应式数据和缓存的实现,主要涉及以下几个点:

  • Vuex 的响应式实现原理;
  • 响应式核心方法 resetStoreVM;
  • commit 和 dispatch 的处理;

本篇,继续介绍 Vuex-namespaced 命名空间的实现;


二,前文梳理

之前几篇,完成了 Vuex 的模块收集、模块安装、响应式数据和缓存;

  • 模块收集:通过 ModuleCollection 类,对 options 选项进行处理,构建“模块树”;
  • 模块安装:处理“模块树”,将各模块中 mutation、action、getter,注册到 store 实例上:_actions、_mutations、_wrappedGetters;将各模块的 State 状态通过 Vue.set 注册到根状态;
  • 响应式数据和缓存:通过resetStoreVM在 store 实例中创建一个 Vue 实例, 借助 Vue 能力将 state、getter 通过 data、computed 进行定义,实现数据的响应式和缓存;

接下来,继续实现 namespaced 命名空间功能;


三,命名空间的使用

1,命名空间介绍

前面已经简单介绍过:在子模块对象中添加 namespaced:true,为模块开启命名空间功能;

开启命名空间功能,相当于为每个模块添加独立的作用域,实现模块间状态和事件的隔离;

2,命名空间的使用

使用官方的 Vuex 插件,以“根模块->模块 A->模块 C”的父子模块关系为例,测试多种使用场景:

1)模块 A 和模块 C 都启用了 namespaced 命名空间:

此时,模块 C 的 changeNum:moduleA/moduleC/changeNum;

AC

2)模块 A 启用了命名空间,但模块 C 没启用命名空间:

此时,模块 C 的 changeNum:moduleA/changeNum;

A

3)模块 C 启用了命名空间,但模块 A 没启用命名空间:

此时,模块 C 的 changeNum:moduleC/changeNum;

C


三,命名空间的实现

1,命名空间的逻辑分析

根据测试情况分析命名空间的划分规则:

在模块注册阶段,会通过类似发布订阅的方式将各模块中的 action、mutation 进行手机并注册,需要根据模块是否开启命名空间状态,为模块拼接命名空间前缀;

所以,可以统一理解为,在事件订阅时,为事件添加对应命名空间标识即可;


2,命名空间的代码实现

在 installModule 模块安装阶段,获取当前模块的命名空间:

// src/vuex/store.js#installModule/*** 安装模块* @param {*} store       容器* @param {*} rootState   根状态* @param {*} path        所有路径* @param {*} module      格式化后的模块对象*/
const installModule = (store, rootState, path, module) => {// 根据当前模块的 path 路径,拼接当前模块的命名空间标识let namespace = store._modules.getNamespaced(path);
}

为 ModuleCollection 类添加 getNamespaced 方法:

// src/vuex/module/module-collection.jsclass ModuleCollection {constructor(options) {this.register([], options);}/*** 根据当前模块的 path 路径,拼接当前模块的命名空间标识* @param {*} path * @returns */getNamespaced(path) {let root = this.root;// 从根模块开始,逐层处理子模块,拼接命名空间标识return path.reduce((str, key) => {// 从根模块查找当前子模块root = root.getChild(key);// 若子模块启用命名空间,拼接命名空间标识并返回结果继续处理return str + (root.namespaced ? key + '/' : '')}, '');}
}

测试getNamespaced获取命名空间:

模块 A、B 都开启命名空间的情况:

模块 A 不开启命名空间,模块 C 开启命名空间的情况:

结论与官方 Vuex 插件相同;

拿到了命名空间后,就需要在注册事件时,为其添加对应的命名空间标识;

在模块安装注册时,为事件添加命名空间标识:

// src/vuex/store.js#installModule/*** 安装模块* @param {*} store       容器* @param {*} rootState   根状态* @param {*} path        所有路径* @param {*} module      格式化后的模块对象*/
const installModule = (store, rootState, path, module) => {// 根据当前模块的 path 路径,拼接当前模块的命名空间标识let namespace = store._modules.getNamespaced(path);if (path.length > 0) {let parent = path.slice(0, -1).reduce((memo, current) => {return memo[current]}, rootState)Vue.set(parent, path[path.length - 1], module.state);}// 遍历 mutationmodule.forEachMutation((mutation, key) => {// 添加命名空间标识: namespace + keystore._mutations[namespace + key] = (store._mutations[namespace + key] || []);store._mutations[namespace + key].push((payload) => {mutation.call(store, module.state, payload);})})// 遍历 actionmodule.forEachAction((action, key) => {// 添加命名空间标识: namespace + keystore._actions[namespace + key] = (store._actions[namespace + key] || []);store._actions[namespace + key].push((payload) => {action.call(store, store, payload);})})// 遍历 gettermodule.forEachGetter((getter, key) => {// 添加命名空间标识: namespace + keystore._wrappedGetters[namespace + key] = function () {return getter(module.state);}})module.forEachChild((child, key) => {installModule(store, rootState, path.concat(key), child);})
}

3,命名空间效果测试

测试示例:

<template><div id="app"><br> 根模块测试: <br>商品数量: {{this.$store.state.num}} 个<br>商品单价: 10 元<br>订单金额: {{this.$store.getters.getPrice}} 元<br><button @click="$store.commit('changeNum',5)">同步更新:数量+5</button><button @click="$store.dispatch('changeNum',-5)">异步更新:数量-5</button><br> 子模块测试: <br>A 模块-商品数量: {{this.$store.state.moduleA.num}} 个<br>B 模块-商品数量: {{this.$store.state.moduleB.num}} 个<br>C 模块-商品数量: {{this.$store.state.moduleA.moduleC.num}} 个<br><button @click="$store.commit('moduleA/changeNum',5)">A 模块-同步更新:数量+5</button><button @click="$store.commit('moduleB/changeNum',5)">B 模块-同步更新:数量+5</button><button @click="$store.commit('moduleA/moduleC/changeNum',5)">C 模块-同步更新:数量+5</button></div>
</template>

点击按钮前(页面初始化完成)

点击按钮后(更新完成)

  • 上边区域对根模块的测试:

点击同步/异步更新按钮,通过$store.commit('changeNum',5)$store.dispatch('changeNum',-5) 操作,只能够影响到根模块中 mutation、action 对应的 changeNum 事件,不再对子模块产生影响;

  • 下边区域对子模块的测试:

点击同步更新按钮,通过$store.commit('moduleA/changeNum',5) 操作,会根据命名空间标识查找对应模块下的changeNum事件;

这样,就实现了不同子模块间状态和事件操作的隔离;


四,核心逻辑梳理

  • 在 ModuleCollection 模块收集类中,提供根据 path 获取命名空间标识的能力:getNamespaced(path)
  • 在 installModule 模块安装时,通过调用getNamespaced(path) 获取当前模块的命名空间标识;
  • 在安装/注册mutationactiongetter 时,为对应的事件添加(拼接)上命名空间标识;

这样,就实现了 Vuex 命名空间 namespaced 功能,即:根模块与各子模块中定义的事件完全独立互不影响;


五,结尾

本篇,主要介绍了 Vuex-namespaced 命名空间的实现,主要涉及以下几个点:

  • 命名空间的介绍和使用;
  • 命名空间的逻辑分析与代码实现;
  • 命名空间核心流程梳理;

下一篇,继续介绍 Vuex 插件的实现

相关文章:

【手写 Vuex 源码】第十篇 - Vuex 命名空间的实现

一&#xff0c;前言 上一篇&#xff0c;主要介绍了 Vuex 响应式数据和缓存的实现&#xff0c;主要涉及以下几个点&#xff1a; Vuex 的响应式实现原理&#xff1b;响应式核心方法 resetStoreVM&#xff1b;commit 和 dispatch 的处理&#xff1b; 本篇&#xff0c;继续介绍 …...

面试腾讯测试岗后感想,真的很后悔这5年一直都干的是基础测试....

前两天&#xff0c;我的一个朋友去大厂面试&#xff0c;跟我聊天时说&#xff1a;输的很彻底… 我问她&#xff1a;什么情况&#xff1f;她说&#xff1a;很后悔这5年来一直都干的是功能测试… 相信许多测试人也跟我朋友一样&#xff0c;从事了软件测试很多年&#xff0c;却依…...

知识图谱 方法、实践与应用 王昊奋 读书笔记(下)

最近读了这本书&#xff0c;在思路上很有启发&#xff0c;对知识图谱有了初步的认识&#xff0c;以下是原书后半部分的内容&#xff0c;可以购买实体书获取更多内容。 知识图谱推理 结合已有规则&#xff0c;推出新的事实&#xff0c;例如持有股份就能控制一家公司&#xff0…...

vue实现打印浏览器页面功能(两种方法)

推荐使用方法二 方法一&#xff1a;通过npm 安装插件 1&#xff0c;安装 npm install vue-print-nb --save 2&#xff0c;引入 安装好以后在main.js文件中引入 import Print from vue-print-nbVue.use(Print); //注册 3&#xff0c;现在就可以使用了 div id"printTest…...

【VictoriaMetrics】VictoriaMetrics单机版批量和单条数据写入(Prometheus格式)

VictoriaMetrics单机版支持以Prometheus格式的数据写入,写入支持单条数据写入以及多条数据写入,下面操作演示下如何使用 1、首先需要启动VictoriaMetrics单机版服务 2、使用postman插入单机版VictoriaMetrics,以当前时间插入数据 地址为 http://victoriaMetricsIP:8428/api…...

【青训营】分布式定时任务简述

这是我参与「第五届青训营 」伴学笔记创作活动的第 13 天 分布式定时任务简述 定义 定时任务是指系统为了自动完成特定任务&#xff0c;实时、延时、周期性完成任务调度的过程。分布式定时任务是把分散的、可靠性差的定时任务纳入统一平台&#xff0c;并且实现集群管理调度和…...

golang语言本身设计点总结

本文参考 1.golang的内存管理分配 golang的内存分配仿造Google公司的内存分配方法TCmalloc算法&#xff1b;她会把将内存请求分为两类,大对象请求和小对象请求,大对象为>32K的对象。 在了解golang的内存分配之前要知道什么事虚拟内存&#xff0c;虚拟内存是把磁盘作为全局…...

PTA L1-046 整除光棍(详解)

前言&#xff1a;内容包括四大模块&#xff1a;题目&#xff0c;代码实现&#xff0c;大致思路&#xff0c;代码解读 题目&#xff1a; 这里所谓的“光棍”&#xff0c;并不是指单身汪啦~ 说的是全部由1组成的数字&#xff0c;比如1、11、111、1111等。传说任何一个光棍都能被…...

将小程序代码转成uni-app代码

最近因为公司项目原因需要将小程序的项目转换成uni—app的项目&#xff0c;所以总结了以下几点&#xff1a; 首先你可以先到uni-app的官网简单看一下对它的介绍&#xff0c;本次文章的介绍是针对简单的微信小程序来进行的转化。 在这之前我们来看一下目录对比 下面就来介绍一下…...

C语言在游戏中播放音乐

使用 mciSendString 播放音乐 mciSendString 支持 mp3、wma、wav、mid 等多种媒体格式&#xff0c;使用非常简单。这里做一个简单的范例&#xff0c;用 mciSendString 函数播放 MP3 格式的音乐&#xff0c;代码如下&#xff1a; // 编译该范例前&#xff0c;请把 music.mp3 放…...

机器学习算法:随机森林

在经典机器学习中&#xff0c;随机森林一直是一种灵丹妙药类型的模型。 该模型很棒有几个原因&#xff1a; 与许多其他算法相比&#xff0c;需要较少的数据预处理&#xff0c;因此易于设置充当分类或回归模型不太容易过度拟合可以轻松计算特征重要性在本文[1]中&#xff0c;我想…...

如何做好多项目全生命周期的资源调配,提升资源利用效率?【橙子】

随着产品研发中心各团队承接的研发项目数量和规模日趋增加&#xff0c;人均产值和利润目标逐步提升&#xff0c;人均承接的项目数量也逐渐增加&#xff0c;目前缺乏合理的研发资源管理方案&#xff0c;存在多项目研发过程中资源冲突及部分项目研发人员忙闲不均等现象&#xff0…...

JVM - 内存分配

目录 JVM的简化架构和运行时数据区 JVM的简化架构 运行时数据区 PC寄存器 Java栈 Java堆 方法区 运行时常量池 本地方法栈 栈、堆、方法区交互关系 Java堆内存模型和分配 Java堆内存概述 Java堆的结构 对象的内存布局 对象的访问定位 Trace跟踪和Java堆的参数配…...

【知识图谱论文】Bi-Link:通过转换器和提示的对比学习桥接来自文本的归纳链接预测

文献题目&#xff1a;Bi-Link: Bridging Inductive Link Predictions from Text via Contrastive Learning of Transformers and Prompts发表期刊&#xff1a;WWW2023代码&#xff1a; https://anonymous.4open.science/r/Bi-Link-2277/. 摘要 归纳知识图的完成需要模型来理解…...

jieba+wordcloud 词云分析 202302 QCon 议题 TOP 关键词

效果图 步骤 &#xff08;1&#xff09;依赖 python 库 pip install jieba wordcloud数据 概览 $ head -n 5 input.txt 中国软件技术发展洞察和趋势预测报告 2023 QCon 大会内容策划思路 FinOps&#xff1a;从概念到落地 开源芯片的发展现状、机遇和未来 乐观者前行&#xff0…...

包管理工具-npm-npx-yarn-cnpm

代码共享方案 在我们通过模块化的方式将代码划分成一个个小的结构后&#xff0c;在以后的开发中我们就可以通过模块化的方式来封装自己的代码&#xff0c;并且封装成一个工具&#xff0c;这个工具我们可以让同事通过导入的方式来使用&#xff0c;甚至你可以分享给世界各地的程…...

go gin学习记录1

环境&#xff1a; MAC M1&#xff0c;Go 1.17.2&#xff0c;GoLand 默认执行指令的终端&#xff0c;如果没有特别说明&#xff0c;指的都是goland->Terminal 创建项目 Goland中新建项目&#xff0c;在$GOPATH/src/目录下建立t_gin项目。 进入项目&#xff0c;在goland的T…...

Docker常用命令

1&#xff1a;帮助命令docker versiondocker infodocker --help2&#xff1a;镜像命令docker images&#xff08;列出本地主机上的镜像&#xff09;各个选项说明:docker imagesREPOSITORY&#xff1a;表示镜docker images像的仓库源TAG&#xff1a;镜像的标签IMAGE ID&#xff…...

论文写作——公式编辑器、latex表格、颜色搭配器

1、公式编辑器(网页版mathtype可用于latex公式编辑): MathType demo - For DevelopersLive demonstration about the features of Mathtype which allows edition equations and formulas (PNG, flash, SVG, PDF, EPS), based on MathML and compatible with LaTeX.https:/…...

MySQL数据库12——视图(VIEW)

视图概念 视图是一个虚拟表&#xff0c;称其为虚拟表的原因是&#xff1a;视图内的数据并不属于视图本身&#xff0c;而属于创建视图时用到的基本表。可以认为&#xff0c;视图是一个表中的数据经过某种筛选后的显示方式&#xff1b;或者多个表中的数据经过连接筛选后的显示方…...

conda相比python好处

Conda 作为 Python 的环境和包管理工具&#xff0c;相比原生 Python 生态&#xff08;如 pip 虚拟环境&#xff09;有许多独特优势&#xff0c;尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处&#xff1a; 一、一站式环境管理&#xff1a…...

Prompt Tuning、P-Tuning、Prefix Tuning的区别

一、Prompt Tuning、P-Tuning、Prefix Tuning的区别 1. Prompt Tuning(提示调优) 核心思想:固定预训练模型参数,仅学习额外的连续提示向量(通常是嵌入层的一部分)。实现方式:在输入文本前添加可训练的连续向量(软提示),模型只更新这些提示参数。优势:参数量少(仅提…...

Java 语言特性(面试系列1)

一、面向对象编程 1. 封装&#xff08;Encapsulation&#xff09; 定义&#xff1a;将数据&#xff08;属性&#xff09;和操作数据的方法绑定在一起&#xff0c;通过访问控制符&#xff08;private、protected、public&#xff09;隐藏内部实现细节。示例&#xff1a; public …...

企业如何增强终端安全?

在数字化转型加速的今天&#xff0c;企业的业务运行越来越依赖于终端设备。从员工的笔记本电脑、智能手机&#xff0c;到工厂里的物联网设备、智能传感器&#xff0c;这些终端构成了企业与外部世界连接的 “神经末梢”。然而&#xff0c;随着远程办公的常态化和设备接入的爆炸式…...

DingDing机器人群消息推送

文章目录 1 新建机器人2 API文档说明3 代码编写 1 新建机器人 点击群设置 下滑到群管理的机器人&#xff0c;点击进入 添加机器人 选择自定义Webhook服务 点击添加 设置安全设置&#xff0c;详见说明文档 成功后&#xff0c;记录Webhook 2 API文档说明 点击设置说明 查看自…...

windows系统MySQL安装文档

概览&#xff1a;本文讨论了MySQL的安装、使用过程中涉及的解压、配置、初始化、注册服务、启动、修改密码、登录、退出以及卸载等相关内容&#xff0c;为学习者提供全面的操作指导。关键要点包括&#xff1a; 解压 &#xff1a;下载完成后解压压缩包&#xff0c;得到MySQL 8.…...

libfmt: 现代C++的格式化工具库介绍与酷炫功能

libfmt: 现代C的格式化工具库介绍与酷炫功能 libfmt 是一个开源的C格式化库&#xff0c;提供了高效、安全的文本格式化功能&#xff0c;是C20中引入的std::format的基础实现。它比传统的printf和iostream更安全、更灵活、性能更好。 基本介绍 主要特点 类型安全&#xff1a…...

Python 高效图像帧提取与视频编码:实战指南

Python 高效图像帧提取与视频编码:实战指南 在音视频处理领域,图像帧提取与视频编码是基础但极具挑战性的任务。Python 结合强大的第三方库(如 OpenCV、FFmpeg、PyAV),可以高效处理视频流,实现快速帧提取、压缩编码等关键功能。本文将深入介绍如何优化这些流程,提高处理…...

Python实现简单音频数据压缩与解压算法

Python实现简单音频数据压缩与解压算法 引言 在音频数据处理中&#xff0c;压缩算法是降低存储成本和传输效率的关键技术。Python作为一门灵活且功能强大的编程语言&#xff0c;提供了丰富的库和工具来实现音频数据的压缩与解压。本文将通过一个简单的音频数据压缩与解压算法…...

大数据治理的常见方式

大数据治理的常见方式 大数据治理是确保数据质量、安全性和可用性的系统性方法&#xff0c;以下是几种常见的治理方式&#xff1a; 1. 数据质量管理 核心方法&#xff1a; 数据校验&#xff1a;建立数据校验规则&#xff08;格式、范围、一致性等&#xff09;数据清洗&…...