vuex 源码分析(七) module和namespaced 详解
当项目非常大时,如果所有的状态都集中放到一个对象中,store 对象就有可能变得相当臃肿。
为了解决这个问题,Vuex允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割。
namespaced表示当前模块是否使用命名空间,如果使用的话,那么设置了namespaced属性的模块将和其它模块独立开来,调用时得指定命名空间后才可以访问得到
例如:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script> <script src="./vuex.js"></script> </head> <body> <div id="app"> <p>count:{{count}}</p> <p>Acount:{{Acount}}</p> <button @click="test1">测试1</button> <button @click="test2">测试2</button> </div> <script> const moduleA ={ //子仓库a state:{count:0}, mutations:{Aincrement(state){state.count++}}, actions:{Aincrement(context){context.commit('Aincrement')}} } const store = new Vuex.Store({ //创建Store实例 modules:{A:moduleA}, state:{count:1}, mutations:{increment(state){state.count++}}, actions:{increment(context){context.commit('increment')}} }) new Vue({ //创建Vue实例 el:"#app", store, //把实例化后的store作为new Vue的一个参数 computed:{ ...Vuex.mapState(['count']), ...Vuex.mapState({Acount:state=>state.A.count}) }, methods:{ ...Vuex.mapActions(['increment','Aincrement']), test1(){ this.increment(); }, test2(){ this.Aincrement(); } } }) </script> </body> </html>
我们在根仓库定义了count状态,在子仓库A也定义了一个count,然后渲染如下:
点击测试1按钮将触发根仓库的increment这个action,点击按钮2将触发子仓库A的Aincrement这个action,分别给当前仓库的count递增1
像上面例子里区分的子module,它的mutations和actions都是和根仓库的等级是一样的,如果子仓库和根仓库的mutation或者action重名了,那么就会合并为一个数字,当触发时都会执行,例如:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script> <script src="https://unpkg.com/vuex@3.1.0/dist/vuex.js"></script> </head> <body> <div id="app"> <p>root.no:{{no}}</p> <p>Amodule.no:{{Ano}}</p> <button @click="test">测试1</button> </div> <script> const store = new Vuex.Store({ state:{no:100}, mutations:{ increment(state,no){state.no+=no;} }, modules:{ A:{ state:{no:50}, mutations:{ increment(state,no){state.no+=100;} } } } }) var app = new Vue({ store, computed:{ ...Vuex.mapState({no:state=>state.no,Ano:state=>state.A.no}) }, methods:{ ...Vuex.mapMutations(['increment']), test(){ this.increment(10); } }, el:'#app' }) </script> </body> </html>
我们点击测试1按钮时将触发根仓库和子仓库A的increment这个mutation,此时页面会将两个对应的no都分别进行更新,这样是不符合逻辑的,最好每个仓库都互不干扰
writer by:大沙漠 QQ:22969969
我们可以给子仓库定义一个namespaced属性,值为true,表示开启命名空间,这样,各个仓库间的mutation、getter就不会有冲突了,例如:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script> <script src="https://unpkg.com/vuex@3.1.0/dist/vuex.js"></script> </head> <body> <div id="app"> <p>root.no:{{no}}</p> <p>Amodule.no:{{Ano}}</p> <button @click="test1">测试1</button> <button @click="test2">测试2</button> </div> <script> const store = new Vuex.Store({ state:{no:100}, mutations:{ increment(state,no){state.no+=no;} }, modules:{ A:{ namespaced:true, state:{no:50}, mutations:{ increment(state,no){state.no+=no;} } } } }) var app = new Vue({ el:'#app', store, computed:{ ...Vuex.mapState({no:state=>state.no,Ano:state=>state.A.no}) }, methods:{ ...Vuex.mapMutations(['increment']), ...Vuex.mapMutations('A',{incrementA:'increment'}), test1(){ this.increment(10); }, test2(){ this.incrementA(100); } } }) </script> </body> </html>
渲染如下:
这里虽然子仓库和根仓库都定义了increment,但是因为子仓库定义了namespaced,所以两个并不会起冲突,namespaced的作用就是将mutation和action和其它模块区分开来,引用时需要指定命名空间才可以
源码分析
module的收集是在Vuex.store()实例化时执行ModuleCollection.register()时完成的,如下:
ModuleCollection.prototype.register = function register (path, rawModule, runtime) { //收集模块 /*略*/ // register nested modules if (rawModule.modules) { //如果rawModule.modules存在(含有子仓库) forEachValue(rawModule.modules, function (rawChildModule, key) { this$1.register(path.concat(key), rawChildModule, runtime); //递归调用register()注册子仓库 }); } };
这样就完成了模块的收集,安装模块时也会对子模块进行判断,如下:
function installModule (store, rootState, path, module, hot) { //安装模块 /*略*/ module.forEachChild(function (child, key) { //如果有子模版 installModule(store, rootState, path.concat(key), child, hot); //则递归调用自身 }); }
这样就完成模块的安装了。
原文地址:https://www.cnblogs.com/greatdesert/p/11424930.html
- python爬虫入门(七)Scrapy框架之Spider类
- python爬虫入门(八)Scrapy框架之CrawlSpider类
- python爬虫入门(九)Scrapy框架之数据库保存
- Numpy 修炼之道(1) —— 什么是 Numpy
- TensorFlow修炼之道(3)——计算图和会话(Graph&Session)
- 1.python简介
- 《Python自然语言处理》答案第三章
- 2.python数据类型
- Miller Rabin算法详解
- 3.python文件操作
- TensorFlow修炼之道(2)——变量(Variable)
- 4.python迭代器生成器装饰器
- 洛谷P2044 [NOI2012]随机数生成器
- 5.python函数
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- PyQt5 技术篇-Dialog窗口增加?问号按钮
- python课题:正弦函数 求圆形的阴影面积
- 华为学习笔记(SSM框架报错篇)
- Python通讯录作业
- 振兴杯试题分析:制作简单的登陆页(一)
- Python作业:BMI评估
- Python笔记
- JavaScript 技术篇-chrome利用ClipboardEvent写入剪切板,没成功的你就差一步
- 搭建一个高可用负载均衡的集群架构(第三部分)
- C语言学习笔记
- JavaScript 技术篇-js获取窗口标题名,获取页面URL地址
- Pyhon海龟绘制木叶村徽章
- MIT大神写给女神的Q版Python画图库—Cutecharts【技术创作101训练营】
- JavaScript 技术篇-js创建dom节点,并设置属性
- 容器中的数据管理