vuex
专门在vue中实现集中式状态(数据)管理的一个Vue插件,对Vue应用中多个组件的共享状态进行集中式的管理(读/写),也是一种组件间通信的方式,且适用于任意组件间通信。
使用场景:
- 多个组件依赖于同一状态
- 来自不同组件的行为需要变更同一状态
搭建Vuex环境
- 创建文件:
src/store/index.js
```javascript // 用于创建vuex中最核心的store
// 引入vuex import Vue from ‘vue’ import Vuex from ‘vuex’
// 使用Vuex插件 Vue.use(Vuex)
// 准备actions,用于响应组件中的动作 const actions = {}
// 准备mutations,用于操作数据(state) const mutations = {}
// 准备state,用于存储数据 const state = {}
// 创建并暴露store export default new Vuex.Store({ actions, // actions:actions mutations, state });
2. 在`main.js`中创建vm时传入`store`配置项```javascriptimport Vue from 'vue'import App from './App.vue'// 引入store,因为store写的是index.js,所以此处不需要写完整的./store/index.js路径import store from './store'new Vue({render: h => h(App),store, // 使用vuex插件之后,就可以使用store配置项了}).$mount('#app')
此时,Vue实例对象vm和所有的组件实例对象vc都可以通过 this.$store获取到store对象,通过store的dispatch('xxx', value)调用actions中配置的方法,通过store的commit('xxx',value)调用mutations中配置的方法,通过state获取到state中配置的具体变量。
Vuex的一般流程为:
- 组件中通过
this.$store.dispatch('xxx', value)调用 actions中配置的方法 - actions的方法中,通过
context.commit('xxx', value)调用 mutations中配置的方法 - mutations的方法中,对
state中的变量进行修改操作

actions可以理解为饭店的服务员:组件调用dispatch告诉actions服务员点菜。服务员可以进行一些判断逻辑,比如客户是否有忌口、厨房是否还有原材料等(发送ajax去菜市场买菜也在这里处理)
mutations可以理解为饭点的厨师:actions中调用commit通知厨师做具体的菜。厨师对state中具体的原材料变量进行处理。
如果actions中没有什么判断逻辑,只是单纯的调用了
commit通知厨师,那么就可以组件中通过commit直接通知厨师做菜。虽然actions中也可以对
state进行操作做菜,但是不推荐这么做。因为页面控制台的Vuex监控插件只会监控mutations对state的改变,不会监控actions。
示例
在index.js文件编写actions、mutations、state:
// .......// 准备actions,用于响应组件中的动作const actions = {// context是一个mini版的store,拥有store的dispatch、commit等相关方法jia(context, value) {context.commit('JIA', value);},jian(context, value) {context.commit('JIAN', value);},jiaOdd(context, value) {if(context.state.sum % 2) {context.commit('JIA', value)}},jiaWait(context, value) {setTimeout(() => {context.commit('JIA', value)}, 500);},demo1(context, value) {// actions中的方法,可以通过dispatch继续调用其他方法。context.dispatch('demo2', value)},demo2(context,value) {context.commit('JIA', value)}}// 准备mutations,用于操作数据(state)const mutations = {// mutations内部的方法名一般用大写JIA(state, value) {state.sum += value},JIAN(state, value) {state.sum -= value}}// 准备state,用于存储数据const state = {sum:0}// .........
组件中调用相关方法:
<template><div><!-- 读取Vuex中的数据 --><h2>当前求和为:{{$store.state.sum}}</h2><select v-model.number="n"><option value="1">1</option><option value="2">2</option><option value="3">3</option></select><button @click="increment">+</button><button @click="decrement">-</button><button @click="incrementOdd">当前求和为奇数再加</button><button @click="incrementWait">等一等再加</button></div></template><script>export default {name:'Count',data() {return {n:1, // 用户选择的数字}},methods: {increment() {// this.$store.dispatch('jia', this.n);// actions中没有其他逻辑,只是调用commit。那么就可以在组件中通过commit直接调用mutations中的方法this.$store.commit('JIA', this.n)},decrement() {// this.$store.dispatch('jian', this.n);this.$store.commit('JIAN', this.n)},incrementOdd() {// 通过dispatch调用actions中的方法this.$store.dispatch('jiaOdd', this.n)},incrementWait() {this.$store.dispatch('jiaWait', this.n)}},}</script>
getters
类似于计算属性,位于store中。当state中的数据需要加工后再使用时,可以使用getters加工。
这个属性是非必须的,可以根据需要添加。
示例:
在index.js中配置getters
// 定义gettersconst getters = {bigSum(state) { // 可以接收到statereturn state.sum * 10; // 需要有返回值}}// 创建并暴露storeexport default new Vuex.Store({actions,mutations,state,getters // 将getters配置到store中});
在页面使用getters:
<template><div><h2>当前求和为:{{$store.state.sum}}</h2><!-- 通过$store.getters获取到getters配置的属性 --><h2>当前求和放大10倍为:{{$store.getters.bigSum}}</h2></div></template>
4个map方法的使用
mapState可以用于帮我们映射state中的数据为计算属性。
mapGetters用于帮我们映射getters中的数据为计算属性。
mapActions用于帮我们生成与actions对话的方法,即包含$store.dispatch(xxx)的函数
mapMutations用于帮我们生成与mutations对话的方法,即包含$store.commit的函数
如果要从state中获取很多属性,直接使用计算属性的写法为:
<template><div><h2>求和:{{he}}</h2><h2>学校:{{xuexiao}}</h2><h2>学科:{{xueke}}</h2></div></template><script>export default {name:'Count',computed: {he() {return this.$store.state.sum;},xuexiao() {return this.$store.state.school;},xueke() {return this.$store.state.subject;}}}</script>
每次都要写this.$store.state.比较繁琐,可以使用mapState进行简写:
<script>// 引入mapStateimport {mapState} from 'vuex'export default {name:'Count',computed: {// mapState是一个对象,需要使用解构语法对其属性进行解构// 此时就相当于在计算属性中定义了he、xuexiao、xueke这些计算属性,冒号后面为映射到的state中的属性...mapState({he:'sum', xuexiao:'school', xueke:'subject'})}}</script>
特别的,如果计算属性和state属性名相同,可以使用数组简写:
<script>// 引入mapStateimport {mapState} from 'vuex'export default {name:'Count',computed: {// ...mapState({sum:'sum', school:'school', subject:'subject'})// 数组简写...mapState(['sum', 'school', 'subject'])}}</script>
同样的,如果要获取getters中的属性,可以使用mapGetters进行简写:
<script>// 引入mapState、mapGettersimport {mapState,mapGetters} from 'vuex'export default {name:'Count',computed: {...mapState(['sum', 'school','subject']),// bigSum() {// return this.$store.getters.bigSum// }// 简写为// ...mapGetters({bigSum:'bigSum'})// 或者简写为...mapGetters(['bigSum'])}}</script>
如果要调用actions中的dispatch方法,直接在methods中写法为:
<template><div><button @click="increment">+</button><button @click="decrement">-</button></div></template><script>export default {name:'Count',data() {return {n:1,}},methods: {incrementOdd() {// 通过dispatch调用actions中的方法this.$store.dispatch('jiaOdd', this.n)},incrementWait() {this.$store.dispatch('jiaWait', this.n)}}}</script>
可以使用mapActions简写$store.dispatch:
<template><div><!-- 使用mapActions时,需要在调用方法时直接将参数传进去 --><button @click="increment(n)">+</button><button @click="decrement(n)">-</button></div></template><script>export default {name:'Count',data() {return {n:1,}},methods: {...mapActions({incrementOdd:'jiaOdd', incrementWait:'jiaWait'}) // 对象写法}}</script>
如果组件中方法名和actions中方法名同名,则在mapActions中同样可以使用数组写法。
同样的,可以使用mapMutations简写$store.commit:
<template><div><!-- 使用mapMutations时,需要在调用方法时直接将参数传进去 --><button @click="incrementOdd(n)">当前求和为奇数再加</button><button @click="incrementWait(n)">等一等再加</button></div></template><script>export default {name:'Count',data() {return {n:1,}},methods: {// mapMutations同样有对象写法、数组写法...mapMutations({increment:'JIA', decrement:'JIAN'}),}}</script>
mapActions和mapMutations使用时,若需要传递参数:需要在模板中绑定事件时传递好参数,否则参数是事件对象。
模块化和命名空间
目的:让代码更好维护,让多种数据分类更加明确。
示例:修改store的index.js
// 定义count组件用到的const countOptiosn = {namespaced: true,actions: {jia(context, value) {// console.log('actions的jia调用了', context, value);context.commit('JIA', value);},jian(context, value) {context.commit('JIAN', value);},jiaOdd(context, value) {if(context.state.sum % 2) {context.commit('JIA', value)}},jiaWait(context, value) {setTimeout(() => {context.commit('JIA', value)}, 500);}},mutations: {JIA(state, value) {// console.log('mutations的JIA调用了', state, value)state.sum += value},JIAN(state, value) {state.sum -= value}},state: {sum:0,school: '庞各庄小学',subject: '数学'},getters: {bigSum(state) {return state.sum * 10;}}}// 定义person组件用到的const personOptions = {namespaced: true,actions: {addLiSi(context, value) {if(value.name === '李四') {context.commit('addUser', value);} else {alert('只能输入李四进行添加')}}},mutations: {addUser(state, value) {state.personList.unshift(value);}},state: {personList: [{id:'001', name:'张三'}]},getters: {}}// 使用Vuex插件Vue.use(Vuex)// 创建并暴露storeexport default new Vuex.Store({// 使用modules进行暴露modules: {countOptions: countOptions,personOptions: personOptions}});
在组件中使用map读取命名空间的数据:
export default {name:'Count',methods: {// 调用countOptions命名空间的mutations...mapMutations('countOptions',{increment:'JIA', decrement:'JIAN'}),// 调用countOptions命名空间的actions...mapActions('countOptions',{incrementOdd:'jiaOdd', incrementWait:'jiaWait'})},computed: {// 读取countOptions命名空间的state...mapState('countOptions',['sum', 'school','subject']),// 读取countOptions命名空间的getters...mapGetters('countOptions',{bigSum:'bigSum'})}}
在组件中直接读取命名空间的数据:
export default {name: 'Person',data() {return {name: ''}},computed: {personList() {// 读取personOptions命名空间的state数据return this.$store.state.personOptions.personList;},countSum() {// 读取countOptions命名空间的getters数据return this.$store.getters['countOptions/bigSum']}},methods: {addUser() {// 调用personOptions命名空间的mutations方法this.$store.commit('personOptions/addUser', {id:nanoid(), name: this.name});this.name = '';},addLiSi() {// 调用personOptions命名空间的actions方法this.$store.dispatch('personOptions/addLiSi',{id:nanoid(), name: this.name});this.name = '';}}}
