是什么:
是一个专为 Vue.js 应用程序开发的状态管理模式。属于全局单例模式管理。
为什么:
- 多个视图依赖于同一状态。
- 来自不同视图的行为需要变更同一状态。
- 适合中大型单页应用,需考虑如何更好地在组件外部管理状态
怎么做:
Vuex 主要有四部分:
- state:包含了
store中存储的各个状态。 - getter: 类似于 Vue 中的计算属性,根据其他 getter 或 state 计算返回值。
- mutation: 一组方法,是改变
store中状态的执行者,只能是同步操作。 - action: 一组方法,其中可以包含异步操作。
Action 类似于 mutation,不同在于:
- Action 提交的是 mutation,而不是直接变更状态。
- Action 可以包含任意异步操作,而Mutation只能且必须是同步操作。
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
count: 0
},
getter: {
doneTodos: (state, getters) => {
return state.todos.filter(todo => todo.done)
}
},
mutations: {
increment (state, payload) {
state.count++
}
},
actions: {
addCount(context) {
// 可以包含异步操作
// context 是一个与 store 实例具有相同方法和属性的 context 对象
}
}
})
// 注入到根实例
new Vue({
el: '#app',
// 把 store 对象提供给 “store” 选项,这可以把 store 的实例注入所有的子组件
store,
template: '<App/>',
components: { App }
})
调用:
this.$store.state.count
this.$store.getters.doneTodosCount
this.$store.commit('increment')
this.$store.dispatch('addCount')
Module
由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。
这时我们可以将 store 分割为模块(module) ,每个模块拥有自己的
state、getters、mutations、actions、甚至是嵌套子模块——从上至下进行同样方式的分割
const moduleA = {
state: { ... },
mutations: { ... },
actions: { ... },
getters: { ... }
}
const moduleB = {
state: { ... },
mutations: { ... },
actions: { ... }
}
const store = new Vuex.Store({
modules: {
a: moduleA,
b: moduleB
}
})
store.state.a // -> moduleA 的状态
store.state.b // -> moduleB 的状态
为了简便起见,Vuex 提供了四个辅助函数方法用来方便的将这些功能结合进组件。
mapStatemapGettersmapMutationsmapActions
示例代码:
import { mapState, mapGetters, mapMutations, mapActions } from 'vuex'
export default {
// ...
computed: {
localComputed () { /* ... */ },
// 使用对象展开运算符将此对象混入外部对象中
...mapState({
// 为了能够使用 `this` 获取局部状态,必须使用常规函数
count(state) {
return state.count + this.localCount
}
}),
...mapGetters({
getterCount(state, getters) {
return state.count + this.localCount
}
})
}
methods: {
...mapMutations({
// 如果想将一个属性另取一个名字,使用以下形式。注意这是写在对象中
add: 'increment' // 将 `this.add()` 映射为`this.$store.commit('increment')`
}),
...mapActions({
add: 'increment' // 将 `this.add()` 映射为 `this.$store.dispatch('increment')`
})
}
}
如果结合进组件之后不想改变名字,可以直接使用数组的方式。
methods: {
...mapActions([
'increment', // 将 `this.increment()` 映射为 `this.$store.dispatch('increment')`
// `mapActions` 也支持载荷:
'incrementBy' // 将 `this.incrementBy(amount)` 映射为 `this.$store.dispatch('incrementBy', amount)`
]),
}
为何使用展开运算符:
mapState等四个函数返回的都是一个对象。我们如何将它与局部计算属性混合使用呢?通常,我们需要使用一个工具函数将多个对象合并为一个,以使我们可以将最终对象传给computed属性。但是有了对象展开运算符,我们就可以进行简化写法。