Vue@2.x系列之Vuex
1. 概述
Vuex 是专门给vue.js使用的状态管理器,其基本作用是为了解决中大型单页应用中组件之间的通信问题。
Vuex主要包括三个核心内容,state(Vue组件的数据),actions(可执行异步代码),mutations(修改state中的数据)。三者之间的关系如下图(该图片来自于官网)
Vuex的核心是store(仓库),储存着应用中大部分state(状态),state的特点如下:
- state是响应式的,如果state发生变化,那么对应的组件会随之更新。
- state不能直接修改,必须通过提交mutation来修改。
2. 快速开始
2.1 安装
npm i vuex --save
2.2 模块化使用
2.2.1 目录结构
2.2.2 mutation-types.js
该文件中包含mutation类型的常量文件。该文件并不是必须的,是否使用取决同时开发项目的成员有多少。如果人员较多可以使用。
export const ADD_LIST = 'ADD_LIST';
export const DELETE_LIST_ITEM = 'DELETE_LIST_ITEM';
2.2.3 mutations.js
导出一个包含一系列可以直接修改state的方法。
import { ADD_LIST } from "./mutation-types";
export default {
// 添加列表项
[ADD_LIST](state) {
state.list = [ ...state.list, `list${state.list.length}`];
}
}
- mutations对象中的方法包含两个参数:
- state — Vuex中的state
- payload — 提交mutation时传入的参数 - 提交mutation:
只能以载荷的方式提交mutation。
store.commit('mutationType', 'somePayload');
2.2.4 actions.js
导出一个包含一些列可以执行异步操作的方法。虽然能够在组件中直接触发action,并且action中也能直接访问到state,但是action中不能直接修改state,如果像修改state,必须调用commit提交mutation,在mutation中修改state。
import { ADD_LIST } from "./mutation-types";
export default {
asyncAdd(context) {
setTimeout(() => {
context.commit(ADD_LIST);
}, 2000);
}
}
- actions对象中的方法两个参数
- context — context是和store实例具有相同属性和方法的上下文对象。
- payload — 触发action时传入的参数。
context是和store实例具有相同属性和方法的上下文对象,所以,
- action中能够访问state;
- action中能够触发其他action;
- action中能够提交mutation;
- action中能够访问getters,和组件中的计算属性类似。
- 触发action
// 以载荷形式触发
store.dispatch('incrementAsync', {
amount: 10
})
// 以对象形式触发
store.dispatch({
type: 'incrementAsync',
amount: 10
})
2.2.5 getters.js
getters和组件的计算属性computed类似。
export default {
increase(state) {
return ++state.count;
}
}
2.2.5 store/index.js
import Vue from 'vue';
import Vuex from 'vuex';
import mutations from './mutations.js';
import actions from './actions.js';
import getters from './getters.js';
Vue.use(Vuex);
export default new Vuex.Store({
state: {
part: 'root',
count: 0,
list: ['list0', 'list1', 'list2']
},
mutations,
actions
getters
});
2.3 src/main.js
将store实例添加到vue实例中,以便实例下的所有组件可以直接通过 this.$store 获取store实例。
import Vue from 'vue';
import App from './App.vue';
import store from './store';
new Vue({
store,
render: h => h(App),
}).$mount('#app');
2.4 src/App.vue
<template>
<div id="app">
<span>测试Vuex</span>
<div class="store-box">
{{partName}}
<br>
increase: {{increase}}
<br>
<button @click="addList">添加</button>
<ul>
<li v-for="(item, index) in list" :key="index">
{{`${item}, ${index}`}}
</li>
</ul>
</div>
</div>
</template>
<script>
import { ADD_LIST } from './store/mutation-types';
import { mapState, mapGetters } from 'vuex';
export default {
name: 'App',
data() {
return {}
},
computed: {
partName() {
return this.$store.state.part;
},
list() {
return this.$store.state.list;
},
increase() {
return this.$store.getters.increase;
}
},
methods: {
// 点击添加按钮,提交mutation
addList() {
this.$store.commit(ADD_LIST);
}
}
}
</script>
2.5 页面效果
点击添加按钮之后的效果:
3. 辅助函数
使用辅助函数获取vuex中的属性或者方法:
import { mapState, mapGetters } from 'vuex';
export default {
...,
computed: {
...mapState({partName: 'part', list: 'list'}),
...mapGetters(['increase', 'decrease'])
},
methods: {
...mapActions([
'increment', // 将 `this.increment()` 映射为 `this.$store.dispatch('increment')`
// `mapActions` 也支持载荷:
'incrementBy' // 将 `this.incrementBy(amount)` 映射为 `this.$store.dispatch('incrementBy', amount)`
]),
...mapActions({
add: 'increment' // 将 `this.add()` 映射为 `this.$store.dispatch('increment')`
}),
...mapMutations([
'increment', // 将 `this.increment()` 映射为 `this.$store.commit('increment')`
// `mapMutations` 也支持载荷:
'incrementBy' // 将 `this.incrementBy(amount)` 映射为 `this.$store.commit('incrementBy', amount)`
]),
...mapMutations({
add: 'increment' // 将 `this.add()` 映射为 `this.$store.commit('increment')`
})
}
...
]