经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » HTML/CSS » HTML5 » 查看文章
vuex 源码分析(七) module和namespaced 详解
来源:cnblogs  作者:大沙漠  时间:2019/9/20 11:08:57  对本文有异议

当项目非常大时,如果所有的状态都集中放到一个对象中,store 对象就有可能变得相当臃肿。

为了解决这个问题,Vuex允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割。

namespaced表示当前模块是否使用命名空间,如果使用的话,那么设置了namespaced属性的模块将和其它模块独立开来,调用时得指定命名空间后才可以访问得到

例如:

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Document</title>
  6. <script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
  7. <script src="./vuex.js"></script>
  8. </head>
  9. <body>
  10.  
  11. <div id="app">
  12. <p>count:{{count}}</p>
  13. <p>Acount:{{Acount}}</p>
  14. <button @click="test1">测试1</button>
  15. <button @click="test2">测试2</button>
  16. </div>
  17. <script>
  18. const moduleA ={ //子仓库a
  19. state:{count:0},
  20. mutations:{Aincrement(state){state.count++}},
  21. actions:{Aincrement(context){context.commit('Aincrement')}}
  22. }
  23. const store = new Vuex.Store({ //创建Store实例
  24. modules:{A:moduleA},
  25. state:{count:1},
  26. mutations:{increment(state){state.count++}},
  27. actions:{increment(context){context.commit('increment')}}
  28. })
  29. new Vue({ //创建Vue实例
  30. el:"#app",
  31. store, //把实例化后的store作为new Vue的一个参数
  32. computed:{
  33. ...Vuex.mapState(['count']),
  34. ...Vuex.mapState({Acount:state=>state.A.count})
  35. },
  36. methods:{
  37. ...Vuex.mapActions(['increment','Aincrement']),
  38. test1(){
  39. this.increment();
  40. },
  41. test2(){
  42. this.Aincrement();
  43. }
  44. }
  45. })
  46. </script>
  47. </body>
  48. </html>

我们在根仓库定义了count状态,在子仓库A也定义了一个count,然后渲染如下:

点击测试1按钮将触发根仓库的increment这个action,点击按钮2将触发子仓库A的Aincrement这个action,分别给当前仓库的count递增1

像上面例子里区分的子module,它的mutations和actions都是和根仓库的等级是一样的,如果子仓库和根仓库的mutation或者action重名了,那么就会合并为一个数字,当触发时都会执行,例如:

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Document</title>
  6. <script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
  7. <script src="https://unpkg.com/vuex@3.1.0/dist/vuex.js"></script>
  8. </head>
  9. <body>
  10. <div id="app">
  11. <p>root.no:{{no}}</p>
  12. <p>Amodule.no:{{Ano}}</p>
  13. <button @click="test">测试1</button>
  14. </div>
  15. <script>
  16. const store = new Vuex.Store({
  17. state:{no:100},
  18. mutations:{
  19. increment(state,no){state.no+=no;}
  20. },
  21. modules:{
  22. A:{
  23. state:{no:50},
  24. mutations:{
  25. increment(state,no){state.no+=100;}
  26. }
  27. }
  28. }
  29. })
  30. var app = new Vue({
  31. store,
  32. computed:{
  33. ...Vuex.mapState({no:state=>state.no,Ano:state=>state.A.no})
  34. },
  35. methods:{
  36. ...Vuex.mapMutations(['increment']),
  37. test(){
  38. this.increment(10);
  39. }
  40. },
  41. el:'#app'
  42. })
  43. </script>
  44. </body>
  45. </html>

我们点击测试1按钮时将触发根仓库和子仓库A的increment这个mutation,此时页面会将两个对应的no都分别进行更新,这样是不符合逻辑的,最好每个仓库都互不干扰

writer by:大沙漠 QQ:22969969

我们可以给子仓库定义一个namespaced属性,值为true,表示开启命名空间,这样,各个仓库间的mutation、getter就不会有冲突了,例如:

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Document</title>
  6. <script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
  7. <script src="https://unpkg.com/vuex@3.1.0/dist/vuex.js"></script>
  8. </head>
  9. <body>
  10. <div id="app">
  11. <p>root.no:{{no}}</p>
  12. <p>Amodule.no:{{Ano}}</p>
  13. <button @click="test1">测试1</button>
  14. <button @click="test2">测试2</button>
  15. </div>
  16. <script>
  17. const store = new Vuex.Store({
  18. state:{no:100},
  19. mutations:{
  20. increment(state,no){state.no+=no;}
  21. },
  22. modules:{
  23. A:{
  24. namespaced:true,
  25. state:{no:50},
  26. mutations:{
  27. increment(state,no){state.no+=no;}
  28. }
  29. }
  30. }
  31. })
  32. var app = new Vue({
  33. el:'#app',
  34. store,
  35. computed:{
  36. ...Vuex.mapState({no:state=>state.no,Ano:state=>state.A.no})
  37. },
  38. methods:{
  39. ...Vuex.mapMutations(['increment']),
  40. ...Vuex.mapMutations('A',{incrementA:'increment'}),
  41. test1(){
  42. this.increment(10);
  43. },
  44. test2(){
  45. this.incrementA(100);
  46. }
  47. }
  48. })
  49. </script>
  50. </body>
  51. </html>

渲染如下:

这里虽然子仓库和根仓库都定义了increment,但是因为子仓库定义了namespaced,所以两个并不会起冲突,namespaced的作用就是将mutation和action和其它模块区分开来,引用时需要指定命名空间才可以

 

 源码分析


 module的收集是在Vuex.store()实例化时执行ModuleCollection.register()时完成的,如下:

  1. ModuleCollection.prototype.register = function register (path, rawModule, runtime) { //收集模块
  2. /**/
  3.  
  4. // register nested modules
  5. if (rawModule.modules) { //如果rawModule.modules存在(含有子仓库)
  6. forEachValue(rawModule.modules, function (rawChildModule, key) {
  7. this$1.register(path.concat(key), rawChildModule, runtime); //递归调用register()注册子仓库
  8. });
  9. }
  10. };

这样就完成了模块的收集,安装模块时也会对子模块进行判断,如下:

  1. function installModule (store, rootState, path, module, hot) { //安装模块
  2. /**/
  3. module.forEachChild(function (child, key) { //如果有子模版
  4. installModule(store, rootState, path.concat(key), child, hot); //则递归调用自身
  5. });
  6. }

这样就完成模块的安装了。

 

原文链接:http://www.cnblogs.com/greatdesert/p/11424930.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号