Vuex 模块化使用详解


Posted in Javascript onJuly 31, 2019

前言 上回我们说了一下 vuex 的简单使用,最后面的时候有说了,由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。

为了解决以上问题,Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割,今天我们也来简单了解一下他的使用,深入学习可能还是要去看官方文档

1 文件结构

文件结构的话,模块化的使用要多一个 modules 的文件夹,里面放着细分模块的 js 文件/模块名文件夹。

这里官方的标准是一个模块一个 js 文件,但是要是模块太复杂的话,也可以把里面的代码拆分出来。

// store 文件夹 
│ actions.js
│ getters.js
│ index.js
│ mutations.js
│ state.js
│
└─modules
  │ moduleB.js
  │
  └─moduleA
      index.js
      mutation.js
      state.js

然后在创建 store 的 js 文件中引入这些模块,直接

import moduleA from './modules/moduleA/index'
import moduleB from './modules/moduleB';

export default new Vuex.Store({
  state,
  getters,
  mutations,
  actions,
  modules: {
    moduleA,
    moduleB,
  }
});

2 模块的局部状态对象的定义

模块内部的 getter,mutation 和 action,他们方法接收的参数会和根状态的不一样,我们一个一个来

getter

getter 的话,他会有三个参数,第一个是模块内的 state,第二个是 模块内的 getters,第三个是根节点状态 rootState,

const getters = {
 bFullName: (state, getters, rootState) => `full${state.bName}`
}

mutation

mutation 里面的回调函数传入的第一个参数也是 模块内的 state,其他和根状态定义的时候一样

const mutations = {
 // 这里的 `state` 对象是模块的局部状态
 SET_B_NAME(state, payload) {
  debugger
  state.bName = payload.name;
 }
}

action

最后的 action 的话,他传入还是只有 context 对象,然后咧,这个对象里面的 state 属性指模块内的状态,rootState 指根状态,如下

const actions = {
 ASYNC_SET_NAME({ state, commit, rootState }, payload) {
  setTimeout(() => {
   state.bName = 'asyncName'
  }, 4000)
 }
}

3 使用

3.1 state 获取

这个的话要在原来状态名前面加一个模块名才能放到到模块内的对象。具体如下

// 原先的基础上加个模块名
this.$store.state.moduleB.bName;
// 辅助函数也一样,name 前面加个模块名 Deno
...mapState({
  name: state => state.moduleB.bName,
})

3.2 命名空间

getter,mutation,action 他们默认都是注册在全局命名空间的,所以我们默认是可以和使用根状态一样去使用他们,但是这样不可避免会出现命名冲突的问题,所以使模块有更高的封装性与复用性,我们可以通过添加 `
namespaced: true` 使其成为带命名空间的模块。当模块被注册后,它的所有 getter、action 及 mutation 都会自动根据模块注册的路径调整命名。

// moduleB 模块导出的时候加个 namespaced: true,
export default {
 namespaced: true,
 state,
 getters,
 mutations,
 actions,
}

3.2.1 辅助函数的使用

因为有了命名空间这么一层封装,所以我们在用辅助函数的时候都要多加那么一层模块名,具体看下面代码。

// getter
this.$store.getters['moduleB/bFullName']; 

...mapGetters({
 bGetter2: 'moduleB/bFullName'
})

// mutation 
this.$store.commit('moduleB/SET_B_NAME', {
 name: 'QQ'
});

...mapMutations({
 setBname: 'moduleB/SET_B_NAME'
}),

// action
this.$store.dispatch('moduleB/ASYNC_SET_NAME', { name: "JJ" });

...mapActions({
 aSetAge: 'moduleB/ASYNC_SET_NAME',
}),

每次都要写模块名,这样写下来很烦,所以这些辅助函数给我们提供了一个参数位来绑定命名空间。

// moduleB 模块内的 bName
...mapState('moduleB', {
 name: state => state.bName
})

// 同理 mapAction mapMutation 也可以这个样子
...mapAction('moduleB',[
 '/ASYNC_SET_NAME'
])

除了这个之外,如果你当前组件用的 vuex 状态都是一个模块的话,我们可以使用 createNamespacedHelpers 创建基于某个命名空间辅助函数,如下:

import { createNamespacedHelpers } from 'vuex'

const { mapState, mapActions } = createNamespacedHelpers('moduleB') // moduleName

这样创建之后,我们就可以用之前的写法来访问到模块的状态。

...mapState({
 bName: state => state.bName,
}),

3.2.2 在带命名空间的模块内访问全局内容

如果你希望使用全局 state 和 getter,rootState 和 rootGetter 会作为第三和第四参数传入 getter,也会通过 context 对象的属性传入 action。

若需要在全局命名空间内分发 action 或提交 mutation,将 { root: true } 作为第三参数传给 dispatch 或 commit 即可。具体看下面代码:

modules: {
 foo: {
  namespaced: true,

  getters: {
   // 在这个模块的 getter 中,`getters` 被局部化了
   // 你可以使用 getter 的第四个参数来调用 `rootGetters`
   someGetter (state, getters, rootState, rootGetters) {
    getters.someOtherGetter // -> 'foo/someOtherGetter 模块内的 getter'
    rootGetters.someOtherGetter // -> 'someOtherGetter 全局的getter'
   },
   someOtherGetter: state => { ... }
  },

  actions: {
   // 在这个模块中, dispatch 和 commit 也被局部化了
   // 他们可以接受 `root` 属性以访问根 dispatch 或 commit
   someAction ({ dispatch, commit, getters, rootGetters }) {
    getters.someGetter // -> 'foo/someGetter'
    rootGetters.someGetter // -> 'someGetter'

    dispatch('someOtherAction') // -> 'foo/someOtherAction' 模块内的 action
    dispatch('someOtherAction', null, { root: true }) // ->'someOtherAction' 全局的 action 

    commit('someMutation') // -> 'foo/someMutation' 模块内的 action
    commit('someMutation', null, { root: true }) // -> 'someMutation' 全局 mutation
   },
   someOtherAction (ctx, payload) { ... }
  }
 }
}

3.2.3 将模块内的 action 注册为全局

这个感觉和维护模块的封装性有点冲突,但是既然作者提出来了,那就学吧,当我们想要我们模块内的某个 action 提升为全局 action 的时候,在他声明的时候,添加 root: true,并将 action 的定义放到 hanler 函数中,具体如下:

const actions = {
  // 模块内 action
  [ASET_AGE]({ commit }, payload) {
    setTimeout(() => {
      commit('SET_B_NAME', payload.name);
    }, 2000)
  },
  // 提升到全局的 action 
  globalAction: {
    root: true,
    handler({ commit }, payload) {
      debugger
      setTimeout(() => {
        commit('SET_B_NAME', payload.name);
      }, 2000)
    }
  }
}

关于模块使用 Vuex 的介绍就说到这里了,这两篇笔记的项目源码我发到了 GitHub 上面,大家可以去看一下,要是项目中有啥不明白的或者我说的有问题的,欢迎大家留言指正。

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

Javascript 相关文章推荐
拥抱模块化的JavaScript
Mar 07 Javascript
Jquery index()方法 获取相应元素索引值
Oct 12 Javascript
模拟多级复选框效果的jquery代码
Aug 13 Javascript
jQuery学习笔记之jQuery构建函数的7种方法
Jun 03 Javascript
学习JavaScript编程语言的8张思维导图分享
Mar 27 Javascript
jQuery实现首页图片淡入淡出效果的方法
Jun 10 Javascript
jQuery简单实现两级下拉菜单效果代码
Sep 15 Javascript
jQuery简单实现iframe的高度根据页面内容自适应的方法
Aug 01 Javascript
简单模拟node.js中require的加载机制
Oct 27 Javascript
AngularJS自定义控件实例详解
Dec 13 Javascript
轻松实现jQuery添加删除按钮Click事件
Mar 13 Javascript
Vue的实例、生命周期与Vue脚手架(vue-cli)实例详解
Dec 27 Javascript
判断“命令按钮”是否被鼠标单击详解
Jul 31 #Javascript
express框架下使用session的方法
Jul 31 #Javascript
ES6中异步对象Promise用法详解
Jul 31 #Javascript
JS实现在线ps功能详解
Jul 31 #Javascript
ES6中定义类和对象的方法示例
Jul 31 #Javascript
Vue+Koa2 打包后进行线上部署的教程详解
Jul 31 #Javascript
简述vue-cli中chainWebpack的使用方法
Jul 30 #Javascript
You might like
php在线生成ico文件的代码
2007/10/09 PHP
php的curl实现get和post的代码
2008/08/23 PHP
显示程序执行时间php函数代码
2013/08/29 PHP
php实现按照权重随机排序数据的方法
2015/01/09 PHP
jQuery动画效果-fadeIn fadeOut淡入浅出示例代码
2013/08/28 Javascript
下拉列表选择项的选中在不同浏览器中的兼容性问题探讨
2013/09/18 Javascript
JS原型、原型链深入理解
2016/02/27 Javascript
JS集成fckeditor及判断内容是否为空的方法
2016/05/27 Javascript
Angularjs结合Bootstrap制作的一个TODO List
2016/08/18 Javascript
详解Angular2中的编程对象Observable
2016/09/17 Javascript
JS判断指定dom元素是否在屏幕内的方法实例
2017/01/23 Javascript
JS 组件系列之 bootstrap treegrid 组件封装过程
2017/04/28 Javascript
python数据结构之二叉树的建立实例
2014/04/29 Python
Python脚本实现代码行数统计代码分享
2015/03/10 Python
Django Admin实现上传图片校验功能
2016/03/06 Python
Python完成毫秒级抢淘宝大单功能
2019/06/06 Python
Python面向对象之私有属性和私有方法应用案例分析
2019/12/31 Python
Python函数的迭代器与生成器的示例代码
2020/06/18 Python
python安装cx_Oracle和wxPython的方法
2020/09/14 Python
CSS3绘制圆角矩形的简单示例
2015/09/28 HTML / CSS
html5教程制作简单画板代码分享
2013/12/04 HTML / CSS
经典c++面试题五
2014/12/17 面试题
C#软件工程师英语面试题
2015/06/07 面试题
土木工程师岗位职责
2013/11/24 职场文书
办公室前台的岗位职责
2013/12/20 职场文书
金融学专科生自我鉴定
2014/02/21 职场文书
电气工程自动化求职信
2014/03/14 职场文书
环境保护与污染治理求职信
2014/07/16 职场文书
农民工工资承诺书大全
2015/05/04 职场文书
小平您好观后感
2015/06/09 职场文书
2019年教师节:送给所有老师的祝福语
2019/09/05 职场文书
CSS3 制作精美的定价表
2021/04/06 HTML / CSS
mysql 8.0.24版本安装配置方法图文教程
2021/05/12 MySQL
Mybatis-plus在项目中的简单应用
2021/07/01 Java/Android
一级电子管军用接收机测评
2022/04/05 无线电
用PYTHON去计算88键钢琴的琴键频率和音高
2022/04/10 Python