深入理解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 相关文章推荐
javascript onkeydown,onkeyup,onkeypress,onclick,ondblclick
Feb 04 Javascript
超级有用的13个基于jQuery的内容滚动插件和教程
Jul 31 Javascript
jQuery页面滚动浮动层智能定位实例代码
Aug 23 Javascript
jQuery之日期选择器的深入解析
Jun 19 Javascript
javascript中数组中求最大值示例代码
Dec 18 Javascript
jquery实现瀑布流效果分享
Mar 26 Javascript
JS返回iframe中frameBorder属性值的方法
Apr 01 Javascript
jQuery移动端图片上传组件
Jun 12 Javascript
canvas轨迹回放功能实现
Dec 20 Javascript
微信小程序实现的贪吃蛇游戏【附源码下载】
Jan 03 Javascript
基于Koa2写个脚手架模拟接口服务的方法
Nov 27 Javascript
jdk1.8+vue elementui实现多级菜单功能
Sep 24 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
java EJB 加密与解密原理的一个例子
2008/01/11 PHP
phpcms模块开发之swfupload的使用介绍
2013/04/28 PHP
探讨多键值cookie(php中cookie存取数组)的详解
2013/06/06 PHP
推荐几款用 Sublime Text 开发 Laravel 所用到的插件
2014/10/30 PHP
CentOS下PHP安装Oracle扩展
2015/02/15 PHP
js获取元素到文档区域document的(横向、纵向)坐标的两种方法
2013/05/17 Javascript
兼容主流浏览器的jQuery+CSS 实现遮罩层的简单代码
2014/10/14 Javascript
javascript实现禁止右键和F12查看源代码
2014/12/26 Javascript
Angularjs基础知识及示例汇总
2015/01/22 Javascript
触屏中的JavaScript事件分析
2015/02/06 Javascript
js实现鼠标滚轮控制图片缩放效果的方法
2015/02/20 Javascript
深入理解JavaScript系列(33):设计模式之策略模式详解
2015/03/03 Javascript
javascript如何定义对象数组
2016/06/07 Javascript
AngularJS模板加载用法详解
2016/11/04 Javascript
JS实现一次性弹窗的方法【刷新后不弹出】
2016/12/26 Javascript
jQuery动态添加li标签并添加属性和绑定事件方法
2018/02/24 jQuery
JS散列表碰撞处理、开链法、HashTable散列示例
2019/02/08 Javascript
JavaScript Date对象功能与用法学习记录
2020/04/28 Javascript
js实现mp3录音通过websocket实时传送+简易波形图效果
2020/06/12 Javascript
vue-cli3项目配置eslint代码规范的完整步骤
2020/09/10 Javascript
Pycharm编辑器技巧之自动导入模块详解
2017/07/18 Python
Python编程之列表操作实例详解【创建、使用、更新、删除】
2017/07/22 Python
python文字转语音的实例代码分析
2019/11/12 Python
Python字典深浅拷贝与循环方式方法详解
2020/02/09 Python
浅谈图像处理中掩膜(mask)的意义
2020/02/19 Python
浅谈TensorFlow中读取图像数据的三种方式
2020/06/30 Python
python实现经典排序算法的示例代码
2021/02/07 Python
matplotlib bar()实现百分比堆积柱状图
2021/02/24 Python
Intersport西班牙:在线体育商店
2019/11/06 全球购物
Linux如何命名文件--使用文件名时应注意
2014/05/29 面试题
我的五年职业生涯规划
2014/01/23 职场文书
大学生通用个人的自我评价
2014/02/10 职场文书
工商局局长个人对照检查材料思想汇报
2014/09/23 职场文书
2014年幼儿园安全工作总结
2014/11/10 职场文书
大学生入党自我鉴定范文
2019/06/21 职场文书
深入探讨opencv图像矫正算法实战
2021/05/21 Python