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); //则递归调用自身
});
}
这样就完成模块的安装了。
vuex 源码分析(七) module和namespaced 详解的更多相关文章
- ZRender源码分析5:Shape绘图详解
回顾 上一篇说到:ZRender源码分析4:Painter(View层)-中,这次,来补充一下具体的shape 关于热区的边框 以圆形为例: document.addEventListener('DO ...
- Jvm(jdk8)源码分析1-java命令启动流程详解
JDK8加载源码分析 1.概述 现在大多数互联网公司都是使用java技术体系搭建自己的系统,所以对java开发工程师以及java系统架构师的需求非常的多,虽然普遍的要求都是需要熟悉各种java开发框架 ...
- jQuery 源码分析(十八) ready事件详解
ready事件是当DOM文档树加载完成后执行一个函数(不包含图片,css等),因此它的触发要早于load事件.用法: $(document).ready(fun) ;fun是一个函数,这样当DOM树加 ...
- jQuery 源码分析(十一) 队列模块 Queue详解
队列是常用的数据结构之一,只允许在表的前端(队头)进行删除操作(出队),在表的后端(队尾)进行插入操作(入队).特点是先进先出,最先插入的元素最先被删除. 在jQuery内部,队列模块为动画模块提供基 ...
- Netty源码分析之Reactor线程模型详解
上一篇文章,分析了Netty服务端启动的初始化过程,今天我们来分析一下Netty中的Reactor线程模型 在分析源码之前,我们先分析,哪些地方用到了EventLoop? NioServerSocke ...
- 10.Spark Streaming源码分析:Receiver数据接收全过程详解
原创文章,转载请注明:转载自 听风居士博客(http://www.cnblogs.com/zhouyf/) 在上一篇中介绍了Receiver的整体架构和设计原理,本篇内容主要介绍Receiver在 ...
- mybatis 源码分析(三)Executor 详解
本文将主要介绍 Executor 的整体结构和各子类的功能,并对比效率: 一.Executor 主体结构 1. 类结构 executor 的类结构如图所示: 其各自的功能: BaseExecutor: ...
- mybatis 源码分析(八)ResultSetHandler 详解
本篇博客就是 myabtis 系列的最后一篇了,还剩 ResultSetHandler 没有分析:作为整个 mybatis 最复杂最繁琐的部分,我不打算按步骤一次详解,因为里面的主要内容就是围绕 re ...
- ZRender源码分析6:Shape对象详解之路径
开始 说到这里,就不得不提SVG的路径操作了,因为ZRender完全的模拟了SVG原生的path元素的用法,很是强大. 关于SVG的Path,请看这里: Path (英文版) 或者 [MDN]SVG教 ...
随机推荐
- Redis系列---redis简介01
一. 本章我们将用简短的几句话来帮助你快速的了解什么是redis,初学者不必深究 1 Redis简介 Remote Dictionary Server(Redis)是一个开源的使用ANSI C语言编写 ...
- 投色子--html demo
这是之前客户想要看的一个效果,不知道放在博客里面有没有关系,当做备份吧. <!DOCTYPE HTML> <html> <head> <meta charse ...
- DQL---条件查询、单行函数、多行函数、分组函数、数据类型
一.DQL 1.基本规则: (1)对于日期型数据,做 *,/ 运算不合法,可以进行 +, - 运算.比如给日期加一天或减一个月,结果仍为一个日期.两个日期间只能为减法,返回两个日期相差的天数,两个日期 ...
- grep命令提示"binary file matches **.log"解决方法
仔细想想,这个问题遇到很多次了,之前一直以为很复杂,一搜索发现解决这么简单,记录一下做备忘. grep test XXX.log Binary file app.log matches 此时使用-a参 ...
- 使用Dynamics 365 CE Web API查询数据加点料及选项集字段常用查询
微软动态CRM专家罗勇 ,回复336或者20190516可方便获取本文,同时可以在第一间得到我发布的最新博文信息,follow me. 紧接上文:配置Postman通过OAuth 2 implicit ...
- Xcode里面如何添加和配置pch文件??
开发工具/原料: 1.Mac 2.Xcode(我这里目前用的Xcode的最新版本Xcode 7.3) PCH文件的部分发展史: 定义:pch全称为“precompiled header”,也就是预编译 ...
- 21.Java基础_String类
String类构造方法 package pack1; //推荐使用直接赋值的方式得到字符串 public class test { public static void main(String[] a ...
- 8. Go语言—指针类型
一.指针类型介绍 普通类型,变量存的就是值,也叫值类型. 获取变量的地址,用&,比如:var a int ,获取a的地址:&a 指针类型,变量存的是一个地址,这个地址存的才是值(指针存 ...
- 多线程时,请求执行不是按顺序的,可添加Critical Section Controller(临界部分控制器),执行顺序是固定的,但执行一段时间后,该逻辑器下的请求不再循环,无解ing
- Centos 7+KVM(Windows Server 2008 r2 )
KVM虚拟机 Kernel-based Virtual Machine的简称,是一个开源的系统虚拟化模块,自Linux 2.6.20之后集成在Linux的各个主要发行版本中.它使用Linux自身的调度 ...