每一个 Vuex应用的核心就是store,而每一个store又是一个Vue的Store对象的实例,所以我们可以在根组件注入store然后通过this.$store访问的store实例。简单的来说,它也是一个普通的js对象。这一点和redux相似。

1.vuex数据模式

vuex数据流方案

vuex的设计思想借鉴了Flux、Redux、和 The Elm Architecture,所以和redux有许多相似之处,在vuex中,更改state只能通过mutation一种途径,vue组件可以dispatch异步的Action,Action通过commit同步的mutation来更改state,我们也可以通过this.$store来获取单一实例,当需要操作多个状态时,通常使用辅助函数mapState、mapMutations、mapActions,详见官文

2.基本配置

1
2
3
4
5
6
7
8
9
10
11
12
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment (state) {
state.count++
}
},
actions: {},
getters: {}
})

state: 初始全局状态值
mutations: 同步处理状态值
actions: 异步数据流处理
getters: 加工处理状态值

3.模块化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// app.js
import Vue from 'vue';
import router from './router';

new Vue ({
router,
store,
// ...
}).$mount ('#app');

// store/index.js
import Vue from 'vue'
import Vuex from 'vuex'

import module1 from './modules/module1'
import module2 from './modules/module2'

Vue.use(Vuex)

export default new Vuex.Store({
modules: {
module1,
module2
}
})

4.State状态

在组件中获取state

由于vuex存储的状态是响应式的,我们获取状态时都应该使用计算属性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// 没有注入到根组件
import store from './store'

const Counter = {
template: `<div>{{ count }}</div>`,
computed: {
count () {
return store.state.count
}
}
}

// 注入到根组件,例如3小结案例
const Counter = {
template: `<div>{{ count }}</div>`,
computed: {
count () {
return this.$store.state.count
}
}
}

// 使用mapState辅助函数 两种方式
computed: mapState({
// 箭头函数可使代码更简练
count: state => state.count,

// 传字符串参数 'count' 等同于 `state => state.count`
countAlias: 'count',

// 为了能够使用 `this` 获取局部状态,必须使用常规函数
countPlusLocalState (state) {
return state.count + this.localCount
}
})

computed: mapState([
// 映射 this.count 为 store.state.count
'count'
])

5.Mutation

更改Vuex中state的唯一方式就是提交mutation,它接受state作为第一个参数。

5.1常用的Mutation方式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
const store = new Vuex.Store({
state: {
count: 1
},
mutations: {
increment (state) {
// 变更状态
state.count++
}
}
})

// 调用
store.commit('increment')
5.2提交参数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// ...
mutations: {
increment (state, n) {
state.count += n
}
}

// 调用
store.commit('increment', 10)

// 对象风格传参
store.commit({
type: 'increment',
amount: 10
})

// 调用
mutations: {
increment (state, payload) {
state.count += payload.amount
}
}
5.4组件中调用mutation

所有的store实例都可以通过this.$store获取,这里对这种方式不做过多诠释,主要是使用辅助函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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')`
})
}
}

6.Action

Action类似于mutation,但不同的是Action提交的是mutation,Action可以包含异步操作,下面案例在actions中使用commit方法调用mutations的方法实现state的更改。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment (state, n) {
state.count += n
},
redce (state, n) {
state.count -= n
}
},
actions: {
addAction(context){
context.commit('increment',10)
},
reduceAction({commit}){
commit('reduce', 1)
}
},
})

组件内使用actions,我们只需要使用vuex提供的辅助函数(mapMutations和mapActions)即可映射对应的actions。

1
2
3
4
5
6
7
8
9
10
11
12
13
import { mapMutations, mapActions } from 'vuex'

export default{
// ...
methods:{
...mapMutations([
'increment','reduce'
]),
...mapActions([
'addAction','reduceAction'
])
},
}

7.Getter

有时我们需要把某些state进行筛选过滤等处理,Getter就派上了用场,想当于组件的计算属性,只有当它依赖的值发生改变时才触发重新计算。

7.1通过属性访问
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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)
}
}
})

// store里面使用
store.getters.doneTodos

// 组件中使用
computed: {
doneTodosCount () {
return this.$store.getters.doneTodosCount
}
}
7.2通过方法访问
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
const store = new Vuex.Store({
state: {
todos: [
{ id: 1, text: '...', done: true },
{ id: 2, text: '...', done: false }
]
},
getters: {
getTodoById: (state) => (id) => {
return state.todos.find(todo => todo.id === id)
}
}
})

// store里面使用
store.getters.getTodoById(2)

// 组件中使用
computed: {
doneTodosCount () {
return this.$store.getters.getTodoById(2)
}
}
7.3mapGetters辅助函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import { mapGetters } from 'vuex'

export default {
// ...
computed: {
// 使用对象展开运算符将 getter 混入 computed 对象中
...mapGetters([
'doneTodosCount',
'anotherGetter',
// ...
])
}
}

// 如果想给getter另取一个名字,可以使用对象的形式。
mapGetters({
// 把 `this.doneCount` 映射为 `this.$store.getters.doneTodosCount`
doneCount: 'doneTodosCount'
})