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, 开启方便使用mapXXX
actions:{},
//....
}
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, 开启方便使用mapXXX
state: {
s_age: 1
}
}
const b = {
namespaced: true, //默认是false, 开启方便使用mapXXX
state: {
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>