0. 参考
1. 前言
本文仅为个人学习笔记,并非教学文章,仅适合在过完文档或其他教程后再来阅读巩固一遍。如需教学文章,可阅读上一部分参考文献。
2. 何为Vuex
Vuex是应用于Vue的状态管理模式[1],或者用一个耳熟能详的词:外挂。Vuex这个外挂为什么要使用?搞懂这个问题才能知道Vuex的由来。
如果不使用Vuex开发,那么组件之间通信用$emit、$refs等语法糖即可搞定。但一旦项目非常大呢?比如100个组件之间通过父子组件通信等方式形成了一张错综复杂的关系网,而这些关系网都要用到共同的数据字段,如时间、地点、人物等。将获取这些数据字段data写在一个组件中,在该组件中用$emit等方式传出去,然后在其他组件中用props或者监听自定义事件的方式等传出去,理论上虽然可以,但一想到还要像走迷宫似的找到传播路径,理清组件辈分关系...理着理着就乱糟糟还容易理错。那么,如果将这些公共数据放到一个外挂中,项目中组件老少咸宜都能用这些数据,就不用再走传播路径迷宫了,这不就省下许多事了?
这就是Vuex的实质。
3. Vuex的五大核心内容
根据官方文档[1],Vuex有五大核心概念:State,Getters,Mutations,Actions,Modules。下文对其一一分解。
3.1 一个简单的实例
以下为官方提供的简单示例代码[1],仅在末尾添加了分号。
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
const store = new Vuex.Store({
state: {
count: 0,
},
mutations: {
increment (state) {
state.count++;
},
},
});
3.2 State
从上述代码来看,实际上可以将state理解为组件中的data。
3.3 Mutations
可以被理解为methods。
3.4 Getters
官方示例代码[1],仅于末尾添加分号。
const store = new Vuex.Store({
state: {
todos: [
{ id: 1, text: '...', done: true },
{ id: 2, text: '...', done: false },
]
},
getters: {
// 是不是很像计算属性?
doneTodos: state => {
return state.todos.filter(todo => todo.done);
},
},
});
可以从代码中看出,getter表现的与计算属性非常相似。
3.5 Actions
官方示例代码[1],仅于末尾添加分号。
const store = new Vuex.Store({
state: {
count: 0,
},
mutations: {
increment (state) {
state.count++;
},
},
actions: {
increment (context) {
context.commit('increment');
},
},
});
同时,根据官方文档,我们可以将actions理解如下:
- 管理
mutations的方法,也就是“方法的方法” - 可以异步的方法(
mutations无法异步)
3.6 Modules
每一组state,mutations,getters与modules均为一个module。当需要定义的数据与状态太多的时候,可以开不只一个外挂(module),可以定义不同的外挂,随用随挂载。
4. 使用Vuex
4.1 全局引入
在根目录中建立一个store文件夹来管理状态,而后在main.js中将其全局引入。示例代码来自博客[2]。
主
// main.js
import Vue from 'vue';
import App from './App';
//引入store
import store from './store';
new Vue ({
el: "#app",
// 重点在这里
store,
components: {
App,
},
template: '<App />',
});
4.2 在组件中使用state
两种方式:
- 使用计算属性
mapState函数
使用计算属性如下(官方代码):
const Counter = {
template: `<div>{{ count }}</div>`,
computed: {
count () {
return store.state.count;
},
},
};
使用mapState()方法如下(官方代码):
// 在单独构建的版本中辅助函数为 Vuex.mapState
import { mapState } from 'vuex';
export default {
// ...
computed: mapState({
// 箭头函数可使代码更简练
count: state => { state.count; },
// 传字符串参数 'count' 等同于 `state => state.count`
countAlias: 'count',
// 为了能够使用 `this` 获取局部状态,必须使用常规函数
countPlusLocalState (state) {
return state.count + this.localCount;
}
})
};
或者可以使用三点符展开:
computed: {
localComputed () { /* ... */ },
// 使用对象展开运算符将此对象混入到外部对象中
...mapState({
// ...
})
}
4.3 在组件中使用getters
使用mapGetters方法
import { mapGetters } from 'vuex';
export default {
// ...
computed: {
// 使用对象展开运算符将 getter 混入 computed 对象中
...mapGetters([
'doneTodosCount',
'anotherGetter',
// ...
]);
},
};
4.4 在组件中使用mutations
使用mapMutations方法
import { mapMutations } from 'vuex';
export default {
// ...
methods: {
...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')`
}),
}
}
4.5 分发actions
同理,在组件中可以用mapActions分发。