深入理解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 相关文章推荐
IE6、IE7中setAttribute不支持class/for/rowspan/colspan等属性
Aug 28 Javascript
js delete 用法(删除对象属性及变量)
Aug 24 Javascript
Js中使用hasOwnProperty方法检索ajax响应对象的例子
Dec 08 Javascript
jQuery多媒体插件jQuery Media Plugin使用详解
Dec 19 Javascript
js+html5通过canvas指定开始和结束点绘制线条的方法
Jun 05 Javascript
JS实现支持Ajax验证的表单插件
Mar 24 Javascript
关于vuex的学习实践笔记
Apr 05 Javascript
vue实现商城购物车功能
Nov 27 Javascript
Javascript中从学习bind到实现bind的过程
Jan 05 Javascript
vue.js使用v-pre与v-html输出HTML操作示例
Jul 07 Javascript
vue下的@change事件的实现
Oct 25 Javascript
在Vue中使用HOC模式的实现
Aug 23 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也可以?成Shell Script
2006/10/09 PHP
php预定义常量
2006/12/25 PHP
Thinkphp搭建包括JS多语言的多语言项目实现方法
2014/11/24 PHP
php判断用户是否手机访问代码
2015/06/08 PHP
给大家分享几个常用的PHP函数
2017/01/15 PHP
PHP进程通信基础之信号量与共享内存通信
2017/02/19 PHP
点击按钮自动加关注的代码(sina微博/QQ空间/人人网/腾讯微博)
2014/01/02 Javascript
jquery链式操作的正确使用方法
2014/01/06 Javascript
jquery插件冲突(jquery.noconflict)解决方法分享
2014/03/20 Javascript
Node.js中创建和管理外部进程详解
2014/08/16 Javascript
详解Webwork中Action 调用的方法
2016/02/02 Javascript
有关easyui-layout中的收缩层无法显示标题的解决办法
2016/05/10 Javascript
jQuery图片前后对比插件beforeAfter用法示例【附demo源码下载】
2016/09/20 Javascript
js字符串与Unicode编码互相转换
2017/05/17 Javascript
vue router带参数页面刷新或回退参数消失的解决方法
2019/02/27 Javascript
用vscode开发vue应用的方法步骤
2019/05/06 Javascript
layui数据表格实现重载数据表格功能(搜索功能)
2019/07/27 Javascript
Layui实现主窗口和Iframe层参数传递
2019/11/14 Javascript
JS正则表达式验证密码强度
2020/03/18 Javascript
[01:11:37]完美世界DOTA2联赛PWL S2 SZ vs FTD.C 第一场 11.19
2020/11/19 DOTA
速记Python布尔值
2017/11/09 Python
用python处理MS Word的实例讲解
2018/05/08 Python
python面向对象多线程爬虫爬取搜狐页面的实例代码
2018/05/31 Python
Python中format()格式输出全解
2019/04/12 Python
500行Python代码打造刷脸考勤系统
2019/06/03 Python
Python获取基金网站网页内容、使用BeautifulSoup库分析html操作示例
2019/06/04 Python
Python并发请求下限制QPS(每秒查询率)的实现代码
2020/06/05 Python
Bandier官网:奢侈、时尚前卫的健身服装首选目的地
2020/07/05 全球购物
酒店总经理助理岗位职责
2014/02/01 职场文书
兰兰过桥教学反思
2014/02/08 职场文书
百年校庆节目主持词
2014/03/27 职场文书
525心理活动总结
2014/07/04 职场文书
出国留学导师推荐信
2015/03/26 职场文书
项目技术负责人岗位职责
2015/04/13 职场文书
JS中如何优雅的使用async await详解
2021/10/05 Javascript
python使用torch随机初始化参数
2022/03/22 Python