vuex
vuex是个插件,用于多个组件操作共享变量
引入:数字操作案例
基于组件自定义事件而实现的操作数字案例如下:
App.vue
<template><div id="app"><input class="num_input" type="text" v-model.number="sum"><!-- 下面是两个按钮 --><AddOne :sum="sum" @MyAddOne="MyAddOne"/><MultiTen :sum="sum" @MyMultiTen="MyMultiTen" /></div>
</template><script>
import AddOne from './components/AddOne.vue';
import MultiTen from './components/MultiTen.vue';export default {name: 'App',components: {AddOne,MultiTen},data() {return {sum: 0}},methods: {MyAddOne(num) {this.sum = num;},MyMultiTen(num) {this.sum = num;}}
}
</script><style>#app {text-align: center;margin: 0 auto;}* {margin-bottom: 1px;}.num_input {text-align: center;}
</style>
AddOne.vue
<div><button @click="addOne">点我加1</button></div>
</template><script>export default{ name: '',props: [ 'sum', 'MyAddOne'],data(){return{}},methods: {addOne() {this.$emit('MyAddOne', this.sum + 1);}},}
</script><style></style>
MultiTen.vue
<div><button @click="mutiTen">点我乘以10</button></div>
</template><script>export default{ name: '',props: [ 'sum'],data(){return{}},methods: {mutiTen() {this.$emit('MyMultiTen', this.sum * 10);}},}
</script>
<style>
</style>
可以看出,对于每个子组件去操作父组件的数据,都需要子组件有触发函数$emit,父组件需要有回调函数,十分麻烦,而vuex对共享变量的管理就显得清晰且简单得多,下面简单介绍一下vuex。
6.1 vuex工作原理
工作原理图(下图来自vuex官网)
state:保存共享的变量
actions:进行一些业务的逻辑,是可选的
mutations:唯一可以操作State中共享变量的地方
getter:state中共享变量的计算属性
举个例子:
Vue Components中通过 this.$store 【–> 调用dispatch(“aa”, 2) --> 触发actions里的 aa 函数 】–> commit(“aa”, 2) -->触发 mutations 的"AA"函数从而去操作state的数据 --> 改变state --> 重新渲染模板
【】中为actions的操作,是可选的
actions中的方法会可以显式传入参数 context 上下文
mutations中的方法需要传入参数 state, 第二个参数payload为可选(如果你想控制你变化数据的大小)
6.2 vuex的简单使用
基于上述的数字操作案例,用vuex实现
6.2.1 导入
vue2的项目应该使用 vuex3版本
npm i vuex@3
vue3的项目应该使用vuex4版本
npm i vuex@4
6.2.2 创建store文件夹及index.js
/store/index.js
import Vue from 'vue'
Vue.use(Vuex)
const store = new Vuex.Store({state: {sum: 1},mutations: {ADD(state, payload) {state.sum += payload;},MULTI(state, payload) {state.sum *= payload;}}});export default store
6.2.3 注册使用
main.js
import App from './App.vue'
import store from './store'new Vue({render: h => h(App),store
}).$mount('#app')
6.2.4 其他
此时,在组件中可以使用 this.$store了
App.vue
<div id="app"><!-- 通过this.$store.state.XXX 可以得到共享变量XXX --><input class="num_input" type="text" v-model.number="this.$store.state.sum"><!-- 下面是两个按钮 --><AddOne /><MultiTen /></div>
</template><script>
import AddOne from './components/AddOne.vue';
import MultiTen from './components/MultiTen.vue';export default {name: 'App',components: {AddOne,MultiTen},
}
</script>
AddOne.vue
<div><button @click="addOne">点我加1</button></div>
</template><script>export default{ name:'',methods: {addOne() {this.$store.commit("ADD", 1)}},}
</script>
MultiTen.vue
<div><button @click="mutiTen">点我乘以10</button></div>
</template><script>export default{ name: '',methods: {mutiTen() {this.$store.commit('MULTI', 10)}},}
</script>
6.3 mapState
mapState可以帮我们在 this.$store.state 定义的共享变量作为计算属性自动生成
6.3.1 使用
导入
import {mapState} from 'vuex'
App.vue
import MultiTen from './components/MultiTen.vue';
import { mapState } from 'vuex';export default {name: 'App',components: {AddOne,MultiTen},computed: {//这下面两个是等价的,都将 sum 作为计算属性sum显示到页面上//1.// sum() {// return this.$store.state.sum;// },//2.//我们直接采用 mapState的数组写法// ...mapState(['sum'])}
}
如果要使用mapState、mapGettters、mapMutations、mapActions ,要求在 this.$store 里定义的东西的名字和在组件中使用的 mapXXX(‘[Name]’) 中的Name名字相同
mapGettters、mapMutations、mapActions 的使用基本同理,但需要在调用的地方传好参数 ,不太方便
举个例子:
/store/index.js
import Vue from 'vue'
Vue.use(Vuex)
const store = new Vuex.Store({state: {sum: 1},mutations: {ADD(state, payload) {state.sum += payload}}});export default store
App.vue
<div id="app"><input class="num_input" type="text" v-model.number="sum"><!-- 需要一开始就定义好参数,所以更适合没参数的方法 --><button @click="ADD(1)">点我加1</button></div>
</template><script>
import { mapState, mapMutations } from 'vuex';export default {name: 'App',computed: {// 需要和 this.$store.state中的sum变量同名...mapState(['sum'])},methods: {// 需要和 this.$store.mutations中的ADD方法同名...mapMutations(['ADD'])}
}
</script>
6.4 Vuex 分模块配置
const a = {namespaced: true //默认是false, 开启方便使用mapXXXactions:{},//....
}
const b = {//...
}export default new Vue.store({modules:{a : [变量1],b : [变量2]}
})
此时,通过组件的 this.$store.state.[模块名] 去获取state对应的内容
通过组件的 this.$store.getters.[‘模块名/对应内容’]去获取getters中的内容
dispatch 和 commit 通过 this.$store.[commit / dispatch](‘模块名/内容名’)
mapState, mapGetters 写成 …mapXXX('模块名 ', [‘数组内容’],)
mapActions 和 mapMutations 需要写成 …mapXXX(‘模块名’,{xx: xx})
举个例子:
/store/index.js
import Vue from 'vue'
Vue.use(Vuex)const a = {namespaced: true, //默认是false, 开启方便使用mapXXXstate: {s_age: 1}
}
const b = {namespaced: true, //默认是false, 开启方便使用mapXXXstate: { t_age: 2},mutations: {ADD_ONE_TEACHER(state) {state.t_age++}}
}
const store = new Vuex.Store({modules: {// 冒号前面的是模块名,后面的是const定义的常量名student : a,teacher : b}});export default store
App.vue
<div id="app"><input class="num_input" type="text" v-model.number="s_age"><input class="num_input" type="text" v-model.number="t_age"><button @click="ADD_ONE_TEACHER(1)">点我加1</button></div>
</template><script>
import { mapState, mapMutations } from 'vuex';export default {name: 'App',computed: {...mapState('teacher', ['t_age']),//以下两种是等效的//1.// s_age() {// return this.$store.state.student.s_age// },//2....mapState('student', ['s_age']),},methods: {//以下两种是等效的//1. // ADD_ONE_TEACHER(num) {// this.$store.commit('teacher/ADD_ONE_TEACHER', num)// },//2....mapMutations('teacher', {ADD_ONE_TEACHER: 'ADD_ONE_TEACHER'})}
}
</script>