当前位置: 首页 > article >正文

Vue模块化-module

由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。

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

注:本文的例子项目结构

src

/store

index.js

​ goods.js

​ todos.js

App.vue

main.js

模块的局部状态管理

这部分主要讲的是,子模块中的getter,mutation,action,都默认给我们提供了哪些参数

以下内容来自官网: Module-模块的局部状态 | Vuex (vuejs.org)

  1. 对于模块内部的 mutationgetter,接收的第一个参数是模块的局部状态对象state

  2. 对于模块内部的 action,接受的第一个参数为context,局部状态通过 context.state 暴露出来,根节点状态则为 context.rootState

  3. 对于模块内部的 getter,根节点状态会作为第三个参数暴露出来:

命名空间

一定要使用命名空间吗?

首先,先思考一个问题,如果想要使用vuex的module模块化,子模块一定要配置命名空间(namespace: true)吗?

答:不一定,子模块不配置namespace仍然可以正常使用;但是正如官网所说,如果不给子模块配置命名空间,那么开发时需要注意以下问题

默认情况下,模块内部的 action 和 mutation 仍然是注册在全局命名空间的——这样使得多个模块能够对同一个 action 或 mutation 作出响应。Getter 同样也默认注册在全局命名空间,但是目前这并非出于功能上的目的(仅仅是维持现状来避免非兼容性变更)。必须注意,不要在不同的、无命名空间的模块中定义两个相同的 getter 从而导致错误

这句话什么意思呢?看下面的例子

举例:

  • vuex入口文件,只配置了modules子模块
// src/store/index.js
import Goods from './goods'
import Todos from './todos'export default new Vuex.Store({modules: {Goods,Todos}
})
  • 子模块goods
export default {namespaced: true,state: {testState: 'goods',},mutations: {testMutation(state) {console.log('goodsMutation');}},actions: {testAction({ commit }) {console.log('goodsAction');}},getters: {testGetters(state) {return 'goods'}}
}
  • 子模块todos
export default {namespaced: true,state: {testState: 'todos',},mutations: {testMutation(state) {console.log('todosMutation');}},actions: {testAction({ commit }) {console.log('testAction');}},getters: {testGetters() {return 'todos'}}
}
  • 测试页面App.vue
<template><div>{{ testState }}{{ testGetters }}<button @click="testMutation">测试testMutation</button><button @click="testAction">测试testAction</button></div>
</template><script>
import { mapMutations, mapGetters, mapState, mapActions } from 'vuex'export default {name: "App",methods: {...mapMutations(["testMutation"]),...mapActions(["testAction"]),  },computed: {...mapGetters(["testGetters"]),...mapState(["testState"])}
};
</script>
  • 结果

看到下面结果可以发现

①对于相同名字state,src/store/index中,哪个模块在上面,使用哪个模块state的数据(已测验,如果Todos在上面,页面显示结果为Todos)

②对于相同方法名getters,直接报错,重复定义

③对于相同方法名mutation,两个都执行

④对于相同方法名action,两个都执行

结论:如果vuex想要使用子模块开发,又不想为命名重复问题考虑过多,我们需要开启namespaced

结果:
在这里插入图片描述

使用命名空间管理子模块

启用了命名空间的 getter 和 action 会收到局部化的 getterdispatchcommit

换言之,你在使用模块内容(module assets)时不需要在同一模块内额外添加空间名前缀。

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

若需要在全局命名空间内分发 action 或提交 mutation,将 { root: true } 作为第三参数传给 dispatchcommit 即可。

  • 访问子模块Goods中的属性

对于mutation,Getters,需要添加前缀Goods

对于state,通过state上的Goods对象访问Goods模块内部的属性

注:前缀值为store/index.js中modules注册模块时的名字

注:需要把 src/store/goods.js和 src/store/todos.js中添加namespaced: true,这里代码省略,只列出App.vue代码

<template><div>{{ testState }}{{ testGetters }}<button @click="testMutation">测试testMutation</button><button @click="testAction">测试testAction</button></div>
</template><script>
import { mapMutations, mapGetters, mapState, mapActions } from 'vuex'export default {name: "App",methods: {...mapMutations({testMutation: 'Goods/testMutation',}),...mapActions({testAction: 'Goods/testAction'})},computed: {...mapGetters({testGetters: 'Goods/testGetters'}),...mapState({testState: state => state.Goods.testState}),}
};
</script>

结果:可以看到 ①getter没有报错,②控制台也只输出了goods的mutation和action ③页面上显示的是goods的state和getter

在这里插入图片描述

子模块使用全局模块的内容

getters

goods模块getter访问全局getter

goods模块getter访问全局state

goods模块getter访问todos的getter

goods模块getter访问todos的state

goods模块访问本模块goods

// src/store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
import Goods from './goods'
import Todos from './todos'Vue.use(Vuex)export default new Vuex.Store({state: {count: 0},getters: {getCount: state => state.count},modules: {Goods,Todos,}
})// src/store/goods.js
export default {namespaced: true,state: {goods: [{ id: 1, type: "apple" },{ id: 2, type: "banana" },]},getters: {getGoodsState(state) {return state.goods[0]},getGlobalGetter(state, getters, rootState, rootGetters) {return rootGetters.getCount},getGlobalState(state, getters, rootState, rootGetters) {return rootState.count},getTodosGetter(state, getters, rootState, rootGetters) {return rootGetters["Todos/getTodosCount"]},getTodosState(state, getters, rootState, rootGetters) {return rootState.Todos.todos[0]},getGoodsGetter(state, getters) {return getters.getGoodsState}}
}// src/store/todos.js
export default {namespaced: true,state: {todos: [{ id: 1, do: "do homework" },{ id: 2, do: "do exercise" },]},mutations: {},actions: {},getters: {getTodosCount: (state) => state.todos[0]}
}
// App.vue
<template><div><ul><li>{{ getGlobalGetter }}</li><li>{{ getGlobalState }}</li><li>{{ getTodosGetter }}</li><li>{{ getTodosState }}</li><li>{{ getGoodsGetter }}</li></ul></div>
</template><script>
import { mapMutations, mapGetters, mapState, mapActions } from 'vuex'export default {name: "App",methods: {},computed: {...mapGetters({getGlobalGetter: 'Goods/getGlobalGetter', // goods模块getter访问全局gettergetGlobalState: 'Goods/getGlobalState', 	// goods模块getter访问全局stategetTodosGetter: 'Goods/getTodosGetter',	// goods模块getter访问Todos的gettergetTodosState: 'Goods/getTodosState',		// goods模块getter访问Todos的stategetGoodsGetter: 'Goods/getGoodsGetter'	// goods模块getter访问Goods的getter}),}
};
</script>

结果:
在这里插入图片描述

action

goods模块action调用全局mutation

goods模块action调用Todos的mutation

// src/store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
import Goods from './goods'
import Todos from './todos'Vue.use(Vuex)export default new Vuex.Store({state: {count: 0},mutations: {addCount(state) {state.count++;}},actions: {addCount2({ commit }) {commit('addCount')}},getters: {getCount: state => state.count},modules: {Goods,Todos,}
})// src/store/goods.js
export default {namespaced: true,state: {goods: [{ id: 1, type: "apple" },{ id: 2, type: "banana" },]},actions: {addTodos({ dispatch, commit, getters, rootGetters }, playload) {commit('addCount', null, { root: true })},addCount({ dispatch, commit, getters, rootGetters }, playload) {commit('Todos/addTodos', null, { root: true })}},mutations: {addGoods(state) {state.goods.push({id: 3, type: "orange"})}}
}// src/store/todos.js
export default {namespaced: true,state: {todos: [{ id: 1, do: "do homework" },{ id: 2, do: "do exercise" },]},actions: {addTodos2({ commit }) {commit('addTodos')}},mutations: {addTodos(state) {state.todos.push({id: 3,do: "play games"})}},getters: {getTodosCount: (state) => state.todos[0]}
}
// App.vue
<template><div><ul><li>{{ count }}</li><li>{{ goods }}</li><li>{{ todos }}</li></ul><button @click="addTodos">addTodos</button><button @click="addCount">addCount</button></div>
</template><script>
import { createNamespacedHelpers, mapState } from 'vuex';
const { mapActions: mapGoodsActions, mapState: mapGoodsState } = createNamespacedHelpers('Goods')
const { mapState: mapTodosState } = createNamespacedHelpers('Todos')export default {name: "App",computed: {...mapState(["count"]),...mapGoodsState(["goods"]),...mapTodosState(["todos"]),},methods: {...mapGoodsActions(["addTodos", "addCount"])},
};
</script>
总结

跨模块访问,主要是前缀的配置以及{root: true}的配置

带命名空间的绑定函数

简而言之,可以对模块名进行提取,避免重复写过长的模块前缀,如some/nested/module/someOtherGetter

官网:Module - 带命名空间的绑定函数| Vuex (vuejs.org)

例如:改写上述getter访问其他模块内容的代码

export default {name: "App",methods: {},computed: {...mapGetters({getGlobalGetter: 'Goods/getGlobalGetter', // goods模块getter访问全局gettergetGlobalState: 'Goods/getGlobalState', 	// goods模块getter访问全局stategetTodosGetter: 'Goods/getTodosGetter',	// goods模块getter访问Todos的gettergetTodosState: 'Goods/getTodosState',		// goods模块getter访问Todos的stategetGoodsGetter: 'Goods/getGoodsGetter'	// goods模块getter访问Goods的getter}),}
};// 方式一,mapGetters添加前缀
export default {name: "App",methods: {},computed: {...mapGetters('Goods',{getGlobalGetter: 'getGlobalGetter',getGlobalState: 'getGlobalState',getTodosGetter: 'getTodosGetter',getTodosState: 'getTodosState',getGoodsGetter: 'getGoodsGetter'}),}
};// 方式二,使用createNamespacedHelpers
// 注:这里重命名 mapGetters->mapGoodsGetters ,防止再引入其他模块,都叫mapGetters冲突
import { createNamespacedHelpers } from 'vuex'
const { mapGetters: mapGoodsGetters } = createNamespacedHelpers('Goods')export default {name: "App",methods: {},computed: {...mapGoodsGetters({getGlobalGetter: 'getGlobalGetter',getGlobalState: 'getGlobalState',getTodosGetter: 'getTodosGetter',getTodosState: 'getTodosState',getGoodsGetter: 'getGoodsGetter'}),}
};

以上就是vuex开启module的内容总结,如果有哪里不明确的地方,欢迎一起交流~~

http://www.lryc.cn/news/2417846.html

相关文章:

  • 动态ip和静态ip有什么区别?
  • Fullcalendar在Vue中的一些使用心得
  • static_cast用法
  • 【001 操作系统】什么是线程、进程?线程进程的区别是什么?
  • 全面解读:大厂牛人详解《数据结构与算法》,附源码笔记,让你轻松掌握核心知识
  • npm 安装淘宝镜像最新2023、nvm安装node报错
  • 2024年全球50家最佳网络安全公司
  • Ubuntu 安装和配置 SSH 服务的简易教程
  • equalsignorecase 和equals的区别
  • NodeJS最新安装和环境配置教程+版本管理(超详细)
  • codec基础知识的学习
  • lwip网络协议基础介绍
  • 程序员的福音—Zeal
  • VMware 安装 CentOS7 图文教程(超详细)
  • 数据平台建设
  • 一文读懂:全网都在说的AIGC到底是什么?
  • 【项目管理】如何开展高质量的团队管理
  • 【正则化的理解】
  • 从头开始学MySQL-------存储过程与存储函数(1)
  • Linux--uboot移植(二)新UBOOT配置
  • 通信协议:HTTP知识点总结
  • VO、DTO、BO、PO、DO、POJO 数据模型的理解和实际使用
  • 360影视大全 python_「www.dy2018.com」python爬取电影天堂(www.dy2018.com)所有视屏的所有链接 - 金橙教程网...
  • 奇异值分解(SVD)详解及其应用
  • JSONP原理以及示例
  • 【802.11】MCS简介
  • sql语句中distinct的用法
  • Netcat使用学习
  • Jfinal 框架简单入门
  • ftp客户端使用详细说明【linux和windows】