title: 使用vuex实现任意组件间通信
date: 2023-07-19 15:51:54
tags:
- vue
categories:
- 工程
- 前端
top:
使用vuex实现任意组件间通信
学习vue的第五天,学到了用插件vuex来实现vue任意组件之间的通信。
以下是个人理解,如有错误请指正。
vuex描述
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式 + 库。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
vuex实现了共享数据的功能,当一个组件想要获取数据时直接向vuex发送请求即可,当一个组件想修改vuex中的数据时可以通过显式调用dispatch和commit来对vuex管理的状态进行修改。
这个图片vuex官网贴的一张vuex内部逻辑图片,左边绿色的是组件
- 当一个组件想要修改vuex管理的数据(state)时,可以 通过调用dispatch方法,需要传递两个参数,第一个是string类型的传入的是Actions中的方法名,第二个是要向方法中传递的参数value。
- 当Actions接收到一个dispatch时,会向自身去寻找是否有第一个参数的方法名,如果没有就提示错误,找到之后就将第二个参数传入该方法。在Actions中的方法一般有两个参数,第一个是context也就是将vuex本身的一些方法包括(commit、state、dispatch······)这些传给方法,方便在逻辑处理之后进行下一步操作,第二个参数就是value,也就是用户传入的数据,如果是单数据就可以直接用,多数据的话可以传对象。
- 在Actions中处理逻辑之后一方面可以再次调用dispatch进行下一个阶段的逻辑处理,另一个是直接调用commit将操作发送到Mutations中。当然组件也可以直接通过commit方法向Mutations传。这里有两个参数,第一个是Mutations中的方法名(string),第二个是要操作的数据。
- Mutations中的方法在检测到有调用时会收到两个参数,第一个是state,也就是vuex储存的数据,第二个是组件要传入的数据。这时就可以进行操作将state中的数据进行更新。
- 当state中的数据更新后,用到数据的组件也会进行重新的渲染。
由于整个流程中只有Mutations中的方法在真正的操作state中的数据,所以vue开发者工具的监测只针对Mutations。在Actions中可以进行一些复杂的逻辑操作,也可以向其他的服务器发送信息等来验证自己的数据是否合理。
vuex安装配置
上面整理完vuex的工作流程,这里是vuex的安装。
通过npm install vuex@3
进行安装即可,这里有一个点是如果使用的是vue2.0的版本,那么vuex就应该下载3.0版本,因为vuex的4.0版本是为vue3.0服务的,所以在npm安装的时候要注意一下选择版本号。
安装完成之后就可以开始配置了。
因为vuex是一个全局的状态管理,有点类似全局事件总线,所以应该将vuex安装在vue实例对象身上,这样任意组件都可以访问到vuex。vuex在vue的配置中叫store
,在创建vue实例的时候将其配置到对象中即可。
可以看到这里有一个store是通过外部引入的,这个就是vuex的配置文件,在src下创建一个store
文件夹,文件夹里创建一个index.js
文件用来写vuex的配置。
插件的安装需要用到Vue.use(),方法,所以在这个文件中也要引入vue。引入vuex之后,可以开始配置了。
上面图中看到vuex的store中有三个主要的内容也可以说是配置对象,就是actions、mutations、state,在文件中创建三个对象
- actions中要写的是用于响应组件中的动作回调函数,组件通过dispatch方法调用actions中的方法,回调函数接收到的参数有两个(context, value),可以完成一些逻辑,然后将操作传向mutations。
- mutations中写的是操作state的函数,会被actions和组件通过commit调用,回调函数接收到的参数有两个(state, value)。
- state中写的就是储存的数据。
- 下面代码也提到了getters配置项,它就像组件中的computed计算属性,将一些计算后的数据返回,组件可以通过getters点得到想要的内容。
写完配置项之后就可以创建store也就vuex实例了,调用Vuex的Store方法,传入前面写好的四个配置项,然后将new出来的store默认暴露即可,之后在main.js中配置到Vue实例对象上,就可以发现实例对象身上出现了一个$store
的值,打开之后就是vuex的方法和state数据。
// store/index.js内容
import Vue from 'vue'
// 引入vuex
import Vuex from 'vuex'
// 使用vuex插件
Vue.use(Vuex)
// 准备actions----用于响应组件中的动作
const actions = {
incrementOdd(context, value){
if(context.state.sum % 2) {
context.commit('INCREMENT', value)
}
},
incrementWait(context, value){
setTimeout(() => {
context.commit('INCREMENT', value)
}, 500);
},
addWangStudent(context, value){
if(value.name[0]!=='王'){
alert('请添加姓王的同学')
} else {
context.commit('ADDSTUDENT', value)
}
}
}
// 准备mutations----用于操作数据(state)
const mutations = {
INCREMENT(state, value){
state.sum += value
},
DECREMENT(state, value){
state.sum -= value
},
ADDSTUDENT(state, value) {
state.students.unshift(value)
}
}
// 准备state----用于储存数据
const state = {
sum:0,
students:[
{id:'001', name:'张三'}
],
}
// 准备getters----用于将state中的数据进行加工
const getters = {
bigSum(state){
return state.sum * 10
}
}
export default new Vuex.Store({
actions,
mutations,
state,
getters
})
vuex使用
单模块
配置完之后就可以使用了,在组件中通过$store
拿到vuex的数据。
-
拿到state数据中的sum数据
this.$store.state.sum
-
拿到getters中的数据
this.$store.getters.bigSum
-
向actions发送
this.$store.dispatch('incrementOdd', this.n)
-
向mutations发送
this.$store.commit('DECREMENT',this.n)
上面是最基本的拿到store中的数据。
下面是去拿这些数据的简写方法也就是vuex的一些封装好的方法
-
导入方法
import {mapState, mapGetters, mapMutations, mapActions} from 'vuex'
-
拿state和getters数据(将数据通过计算属性拿到之后就可以在模板中直接调用),这里mapState和mapGetters拿到的数据是函数对象,通过...将对象展开到计算属性中。
computed: { // 借助mapState生成计算属性,从state中读取数据。(对象写法) // ...mapState({sum:'sum'}) // 借助mapState生成计算属性,从state中读取数据。(数组写法) ...mapState(['sum']), // 借助mapGetters生成计算属性,从getters中读取数据。(对象写法) // ...mapGetters({bigSum:'bigSum'}) // 借助mapGetters生成计算属性,从getters中读取数据。(数组写法) ...mapGetters(['bigSum']) },
-
通过mapMutations和mapActions生成调用函数,这里生成的函数可以有传参,不过需要在标签调用时直接传入,否则会将事件event传入。
methods: { // 自己写的方法调用commit // increment(){ // this.$store.commit('INCREMENT',this.n) // }, // decrement(){ // this.$store.commit('DECREMENT',this.n) // }, // 借助mapMutations生成对应的方法,方法会调用commit方法联系mutations(对象写法) // 需要调用时传参value,否则传参为event ...mapMutations({increment:'INCREMENT', decrement:'DECREMENT'}), // 借助mapMutations生成对应的方法,方法会调用commit方法联系mutations(数组写法) // ...mapMutations(['INCREMENT','DECREMENT']) // 自己写的方法调用dispatch // incrementOdd(){ // this.$store.dispatch('incrementOdd', this.n) // }, // incrementWait(){ // this.$store.dispatch('incrementWait', this.n) // }, // 借助mapActions生成对应的方法,方法会调用dispatch方法联系actions(对象写法) // 需要调用时传参value,否则传参为event // ...mapActions({incrementOdd:'incrementOdd', incrementWait:'incrementWait'}), // 借助mapActions生成对应的方法,方法会调用dispatch方法联系actions(数组写法) ...mapActions(['incrementOdd','incrementWait']) },
多模块
上面的store配置是单模块的,如果多人开发,就会出现冲突问题,下面通过命名空间多模块,来解决。
index.js中
- 将两个组件的数据分别配置在两个对象中,打开namespaced配置为true,在下面new store时传入模块。
import Vue from 'vue'
// 引入vuex
import Vuex from 'vuex'
// 使用vuex插件
Vue.use(Vuex)
const countOptions = {
namespaced:true,
actions:{
incrementOdd(context, value){
if(context.state.sum % 2) {
context.commit('INCREMENT', value)
}
},
incrementWait(context, value){
setTimeout(() => {
context.commit('INCREMENT', value)
}, 500);
},
},
mutations:{
INCREMENT(state, value){
state.sum += value
},
DECREMENT(state, value){
state.sum -= value
},
},
state:{
sum:0,
},
getters:{
bigSum(state){
return state.sum * 10
}
}
}
const studentOptions = {
namespaced:true,
actions:{
addWangStudent(context, value){
if(value.name.indexOf('王')===0){
context.commit('ADDSTUDENT', value)
} else {
alert('请添加姓王的同学')
}
}
},
mutations:{
ADDSTUDENT(state, value) {
state.students.unshift(value)
}
},
state:{
students:[
{id:'001', name:'张三'}
],
},
getters:{
firstStudentName(state){
return state.students[0].name
}
}
}
export default new Vuex.Store({
modules: {
countOptions,
studentOptions
}
})
组件中调用时
-
简写方式,在mapState函数中传入第一个参数,也就是模块的命名名称。
...mapState('countOptions',['sum']), ...mapGetters('countOptions',['bigSum']), ...mapMutations('countOptions',{increment:'INCREMENT', decrement:'DECREMENT'}), ...mapActions('countOptions',['incrementOdd','incrementWait']),
-
未简写方式
// 获取state中的数据时需要先获取命名对象,再获取想要的数据 this.$store.state.countOptions.sum // 获取getters时需要在getters的对象名称前加上命名名称/ this.$store.getters['studentOptions/firstStudentName'] // 向actions和mutations传时需要修改传入的第一个参数,在方法名前加上命名名称/ this.$store.commit('studentOptions/ADDSTUDENT', studentObj) this.$store.dispatch('studentOptions/addWangStudent', studentObj)