深入理解Vuex 模块化(module)


Posted in Javascript onSeptember 26, 2017

一、为什么需要模块化

前面我们讲到的例子都在一个状态树里进行,当一个项目比较大时,所有的状态都集中在一起会得到一个比较大的对象,进而显得臃肿,难以维护。为了解决这个问题,Vuex允许我们将store分割成模块(module),每个module有自己的state,mutation,action,getter,甚至还可以往下嵌套模块,下面我们看一个典型的模块化例子

const moduleA = {
 state: {....},
 mutations: {....},
 actions: {....},
 getters: {....}
}

const moduleB = {
 state: {....},
 mutations: {....},
 actions: {....},
 getters: {....}
}

const store = new Vuex.Store({
 modules: {
 a: moduleA,
 b: moduleB
 }
})

store.state.a // moduleA的状态
store.state.b // moduleB的状态

二、模块的局部状态

模块内部的mutation和getter,接收的第一参数(state)是模块的局部状态对象,rootState

const moduleA = {
 state: { count: 0},
 mutations: {
 increment (state) {
  // state是模块的局部状态,也就是上面的state
  state.count++
 }
 },
 getters: {
 doubleCount (state, getters, rootState) {
  // 参数 state为当前局部状态,rootState为根节点状态
  return state.count * 2
 }
 },
 actions: {
 incremtnIfOddRootSum ( { state, commit, rootState } ) {
  // 参数 state为当前局部状态,rootState为根节点状态
  if ((state.cont + rootState.count) % 2 === 1) {
  commit('increment')
  }
 }
 }
}

三、命名空间(这里一定要看,不然有些时候会被坑)

上面所有的例子中,模块内部的action、mutation、getter是注册在全局命名空间的,如果你在moduleA和moduleB里分别声明了命名相同的action或者mutation或者getter(叫some),当你使用store.commit('some'),A和B模块会同时响应。所以,如果你希望你的模块更加自包含和提高可重用性,你可以添加namespaced: true的方式,使其成为命名空间模块。当模块被注册后,它的所有getter,action,mutation都会自动根据模块注册的路径调用整个命名,例如:

const store = new Vuex.Store({
 modules: {
 account: {
  namespaced: true,
  state: {...}, // 模块内的状态已经是嵌套的,namespaced不会有影响
  getters: {  // 每一条注释为调用方法
  isAdmin () { ... } // getters['account/isAdmin']
  },
  actions: {
  login () {...} // dispatch('account/login')
  },
  mutations: {
  login () {...} // commit('account/login')
  },
  modules: {  // 继承父模块的命名空间
  myPage : {
   state: {...},
   getters: {
   profile () {...}  // getters['account/profile']
   }
  },
  posts: { // 进一步嵌套命名空间
   namespaced: true,
   getters: {
   popular () {...} // getters['account/posts/popular']
   }
  }
  }
 }
 }
})

启用了命名空间的getter和action会收到局部化的getter,dispatch和commit。你在使用模块内容时不需要再同一模块内添加空间名前缀,更改namespaced属性后不需要修改模块内的代码。

四、在命名空间模块内访问全局内容(Global Assets)

如果你希望使用全局state和getter,roorState和rootGetter会作为第三和第四参数传入getter,也会通过context对象的属性传入action若需要在全局命名空间内分发action或者提交mutation,将{ root: true }作为第三参数传给dispatch或commit即可。

modules: {
 foo: {
 namespaced: true,
 getters: {
  // 在这个被命名的模块里,getters被局部化了
  // 你可以使用getter的第四个参数来调用 'rootGetters'
  someGetter (state, getters, rootSate, rootGetters) {
  getters.someOtherGetter // -> 局部的getter, ‘foo/someOtherGetter'
  rootGetters.someOtherGetter // -> 全局getter, 'someOtherGetter'
  }
 },
 actions: {
  // 在这个模块里,dispatch和commit也被局部化了
  // 他们可以接受root属性以访问跟dispatch和commit
  smoeActino ({dispatch, commit, getters, rootGetters }) {
  getters.someGetter // 'foo/someGetter'
  rootGetters.someGetter // 'someGetter'
  dispatch('someOtherAction')  // 'foo/someOtherAction'
  dispatch('someOtherAction', null, {root: true}) // => ‘someOtherAction'
  commit('someMutation') // 'foo/someMutation'
  commit('someMutation', null, { root: true }) // someMutation
  }
 }
 }
}

五、带命名空间的绑定函数

前面说过,带了命名空间后,调用时必须要写上命名空间,但是这样就比较繁琐,尤其涉及到多层嵌套时(当然开发中别嵌套太多,会晕。。)

下面我们看下一般写法

computed: {
 ...mapState({
 a: state => state.some.nested.module.a,
 b: state => state.some.nested.module.b
 }),
 methods: {
 ...mapActions([
  'some/nested/module/foo',
  'some/nested/module/bar'
 ])
 }
}

对于这种情况,你可以将模块的命名空间作为第一个参数传递给上述函数,这样所有的绑定会自动将该模块作为上下文。简化写就是

computed: {
 ...mapStates('some/nested/module', {
 a: state => state.a,
 b: state => state.b
 })
},
methods: {
 ...mapActions('some/nested/module',[
 'foo',
 'bar'
 ])
}

六、模块重用

有时我们可能创建一个模块的多个实例,例如:

  • 创建多个store,他们共用一个模块
  • 在一个store中多次注册同一个模块

如果我们使用一个纯对象来声明模块的状态,那么这个状态对象会通过引用被共享,导致数据互相污染。
实际上Vue组件内data是同样的问题,因此解决办法也是一样的,使用一个函数来声明模块状态(2.3.0+支持)

const MyModule = {
 state () {
 return {
  foo: 'far'
 }
 }
}

七、总结

到这里模块化(module)的内容就已经讲完了,本次主要讲解了module出现的原因,使用方法,全局和局部namespaced模块命名空间,局部访问全局内容,map函数带有命名空间的绑定函数和模块的重用。

引用

https://vuex.vuejs.org Vuex官方文档

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
一个cssQuery对象 javascript脚本实现代码
Jul 21 Javascript
JQuery插件开发示例代码
Nov 06 Javascript
JavaScript中的alert()函数使用技巧详解
Dec 29 Javascript
JavaScript简单生成 N~M 之间随机数的方法
Jan 13 Javascript
js仿微博动态栏功能
Feb 22 Javascript
微信小程序实现登录页云层漂浮的动画效果
May 05 Javascript
vue-cli3 项目从搭建优化到docker部署的方法
Jan 28 Javascript
详解vue移动端项目代码拆分记录
Mar 15 Javascript
layui的面包屑或者表单不显示的解决方法
Sep 05 Javascript
js页面加载后执行的几种方式小结
Jan 30 Javascript
JavaScript canvas绘制折线图
Feb 18 Javascript
javascript设计模式 ? 观察者模式原理与用法实例分析
Apr 22 Javascript
JavaScript实现的仿新浪微博原生态输入字数即时检查功能【兼容IE6】
Sep 26 #Javascript
JavaScript实现离开页面前提示功能【附jQuery实现方法】
Sep 26 #jQuery
Vue from-validate 表单验证的示例代码
Sep 26 #Javascript
微信小程序之蓝牙的链接
Sep 26 #Javascript
jQuery EasyUI Layout实现tabs标签的实例
Sep 26 #jQuery
jQuery EasyUI开发技巧总结
Sep 26 #jQuery
jQuery 开发之EasyUI 添加数据的实例
Sep 26 #jQuery
You might like
php跨站攻击实例分析
2014/10/28 PHP
js动态为代码着色显示行号
2013/05/29 Javascript
jQuery中ajax的get()方法用法实例
2014/12/26 Javascript
JS中的THIS和WINDOW.EVENT.SRCELEMENT详解
2015/05/25 Javascript
Bootstrap的图片轮播示例代码
2015/08/31 Javascript
基于css3新属性transform及原生js实现鼠标拖动3d立方体旋转
2016/06/12 Javascript
bootstrap中使用google prettify让代码高亮的方法
2016/10/21 Javascript
VUE使用vuex解决模块间传值问题的方法
2017/06/01 Javascript
React-Native之定时器Timer的实现代码
2017/10/04 Javascript
详解vue-cli项目中用json-sever搭建mock服务器
2017/11/02 Javascript
3种vue路由传参的基本模式
2018/02/22 Javascript
Vue2.0子同级组件之间数据交互方法
2018/02/28 Javascript
js实现点赞效果
2020/03/16 Javascript
教你用Python脚本快速为iOS10生成图标和截屏
2016/09/22 Python
Python Nose框架编写测试用例方法
2017/10/26 Python
Python探索之自定义实现线程池
2017/10/27 Python
python使用os.listdir和os.walk获得文件的路径的方法
2017/12/16 Python
python爬虫爬取淘宝商品信息
2018/02/23 Python
Python cookbook(数据结构与算法)从序列中移除重复项且保持元素间顺序不变的方法
2018/03/13 Python
Python网络编程使用select实现socket全双工异步通信功能示例
2018/04/09 Python
python自动截取需要区域,进行图像识别的方法
2018/05/17 Python
Python实现的读取电脑硬件信息功能示例
2018/05/30 Python
python中的列表与元组的使用
2019/08/08 Python
python 实现仿微信聊天时间格式化显示的代码
2020/04/17 Python
python 利用matplotlib在3D空间中绘制平面的案例
2021/02/06 Python
使用Python快速打开一个百万行级别的超大Excel文件的方法
2021/03/02 Python
canvas实现圆形进度条动画的示例代码
2017/12/26 HTML / CSS
html5实现输入框fixed定位在屏幕最底部兼容性
2020/07/03 HTML / CSS
法国低价在线宠物商店:bitiba.fr
2020/07/03 全球购物
运动会广播稿30字
2014/01/21 职场文书
反腐倡廉警示教育活动心得体会
2014/09/04 职场文书
推普周国旗下讲话稿
2014/09/21 职场文书
学习焦裕禄精神践行三严三实心得体会
2014/10/13 职场文书
考试作弊检讨
2015/01/27 职场文书
幼儿园心得体会范文
2016/01/21 职场文书
javascript中Set、Map、WeakSet、WeakMap区别
2022/12/24 Javascript