Vuex

概念

在Vue中实现集中式状态(数据)管理的一个Vue的插件,对Vue应用中多个组件的共享状态进行集中式管理(读/写),也是一种组件间通信的方式,且适用于任意组件间的通信。
image

使用场景

多个组件需要共享数据时。

搭建Vuex环境

ps:vue2只能使用Vuex3,Vue3只能使用Vue4

1. 创建文件:src/store/index.js

//引入Vue核心库
import Vue from 'vue'
//引入Vuex
import Vuex  from 'vuex'
Vue.use(Vuex)

//准备actions用于响应组件中的动作
const actions = {}
//准备mutations用于操作数据(state)
const mutations = {}
//准备state用于存储数据
const state = {}

//创建并暴露store, store用于管理上面三个对象
export  default new Vuex.Store({
    actions,
    mutations,
    state
})

2. 在main.js中创建vm时传入store配置项

...
//引入store
import store from './store'
...

// 创建Vue实例对象 
new Vue({
  render: h => h(App),
  store,
}).$mount('#app')

3.组件中读取vuex的数据

$store.state.xxx

4.组件中修改vuex中的数据

//当有业务逻辑时(需要对数据进行判断再做操作时)
$store.dispatch('actions中的方法名', 数据)

//当数据可以直接提交时
$store.commit('mutations中的方法名', 数据)

getters的使用

概念

state中的数据需要经过加工再使用时,可以使用getters,类似于computed

1. 在store/index.js中追加getters配置

const getters = {
    bigSum(state) {
	    //用return的方式返回数据
	    return state.sum * 10
	}
}
...
export default new Vuex.Store({
    ...
	getters
})

2. 在组件中读取数据

$store.getters.bigSum

四个map方法的使用

映射

一开始我们在模板中读取state中的数据,例如:

this.$store.state.sum

但是vue追求简单的模板语法,如果多个模板用到state中的数据,模板则会变得非常复杂。
然后我们使用计算属性从state中读取数据,例如:

computed: {
	...
	school() {
		return this.$store.state.school
	},
	subject() {
		return this.$store.state.subject
	}
	bigSum() {
		return this.$store.getters.bigSum
	}
	...
}

虽然这样模板中可以直接使用计算属性,精简很多,但是可以看出计算属性中代码又过于繁琐,且重复。
由此诞生了map方法。

1. mapState

用于帮助我们映射state中的数据作为计算属性。

computed: {
	//借助mapState生成计算属性: sum,school、subject
	//对象写法
	//({生成的计算属性名: '读取的属性名'})
	...mapState({sum: 'sum', school: 'school', subject: 'subject'})

	//数组写法
	//生成的计算属性名得与读取的属性名一致
	...mapState(['sum', 'school', 'subject'])
}

ps:vue开发者工具里会将mapState里的属性放在 vuex bindings里,而不是computed里,mapGetters同理。

2. mapGetters

用于帮我们映射getters中的数据作为计算属性。

computed: {
	//对象写法
	...mapGetters({bigSum: 'bigSum'})

	//数组写法
	...mapGetters(['bigSum'])
}

对话

我们在methods中与mutationsactions对话的方法是:

methods: {
	increment() {
		this.$store.commit('JIA', this.n)
	},
	decrement() {
		this.$store.commit('JIAN', this.n)
	},
	incrementOdd() {
		this.$store.dispatch('jiaOdd', this.n)
	},
	incrementWait() {
		this.$store.dispatch('jiaWait', this.n)
	}
}

还是同样的问题,重复代码较多。

1. mapMutations

用于帮我们生成mutations对话的方法,即:包含$store.commit(xxx)

对象写法

//模板
<!-- 用map方法需要在模板中传参,不传无法读取n值,并且默认传过去一个event事件 -->
    <button @click="increment(n)">+</button>
    <button @click="decrement(n)">-</button>

//方法
methods: {
	//借助mapMutations生成对应的方法,方法中会调用commit去联系mutations
	//{方法名: 提交的方法名}
	//需要在模板中传参数n,否则默认传过去event事件
	...mapMutations({ increment: 'JIA', decrement: 'JIAN' }),
}

数组写法

//模板
<button @click="JIA(n)">++</button>
<button @click="JIAN(n)">--</button>

//方法
// 方法名得与mutations中的方法名一致
methods: {
	...mapMutations(['JIA', 'JIAN']),
}

2. mapActions

用于帮我们生成actions对话的方法,即:包含$store.dispatch(xxx)

对象写法

//模板
<button @click="incrementOdd(n)">奇数时+1</button>
<button @click="incrementWait(n)">等一等再加</button>

//方法
// 借助mapActions生成对应的方法,方法中会调用dispatch去联系actions(对象写法)
methods: {
	...mapActions({ incrementOdd: 'jiaOdd', incrementWait: 'jiaWait' })
}

数组写法

//模板
<button @click="jiaOdd(n)">奇数时++1</button>
<button @click="jiaWait(n)">等一一等再加</button>

//方法
// 方法名得与mutations中的方法名一致
methods: {
	...mapActions(['jiaOdd','jiaWait'])
}

vuex模块化+命名空间

目的

让代码更好维护,让多种数据分类更加明确。

如何模块化?

1. 创建功能不同的模块js

举例:
count.js

//求和相关配置
export default {
    // 默认为false,true了后才能被其他组件读取该模块
    namespaced: true,//命名空间
    actions: {...},
    mutations: {...},
    state: {...},
    getters: {...}
}

person.js

//人员相关配置
export default {
    namespaced: true,//命名空间
    actions: {...},
    mutations: {...},
    state: {...},
    getters: {...}
}

index.js

//引入Vue核心库
import Vue from 'vue'
//引入Vuex
import Vuex from 'vuex'
Vue.use(Vuex)

import countOptions from './count'
import personOptions from './person'

export default new Vuex.Store({
    //模块化
    modules: {
        countAbout: countOptions,
        personAbout: personOptions
    }
})

2. 开启命名空间后,组件中读取state数据

//方式一,自己直接读取
this.$store.state.personAbout.personList
//方式二,借助mapState读取,读取personAbout模块的personList
...mapState('personAbout', ['personList']),

3. 开启命名空间后,组件中读取getters数据

//方式一
//读取带斜线的属性不能用getters.personAbout/firstPersonName
//js语法,可以使用['']读取属性
this.$store.getters['personAbout/firstPersonName']
//方式二,借助mapGetters读取
...mapGetters('personAbout', ['firstPersonName'])

4. 开启命名空间后,组件中调用dispatch

//方式一
this.$store.dispatch('personAbout/addPersonWang', person)
//方式二,借助mapActions
...mapActions('personAbout', ['addPersonWang'])

5. 开启命名空间后,组件中调用commit

//方式一
this.$store.commit('personAbout/ADD_PERSON', person)
//方式二,借助mapActions
...mapMutations('personAbout', ['ADD_PERSON'])