简介
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新
我们不能直接改变 store 中的状态。改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation。
安装
vuex的安装1
2
3
4
5//npm 方式引入
npm install vuex --save
//yarn 方式引入
yarn add vuex
vuex 基本概念
vuex最主要的几个核心概念就是State,Getter,Mutations,Actions
(一) State
state就是Vuex中的公共的状态, 可以将state看作是所有组件的data, 用于保存所有组件的公共数据,这里面的数据是响应式的,当很多地方引用了同state数据源并且未对数据进行深拷贝,那么当一个地方改变该数据,所有引用的地方数据都会发生变化。
1
2
3
4
5
6
7
8
9
10
11
12
13//定义
import Vuex from 'vuex'
import Vue from 'vue'
Vue.use(Vuex)
const store = new Vuex.Store({
state:{
todoList:[1,2,3]
}
})
//组件获取
this.$store.state.todoList
(二) Getter
Getter是对state里面的数据进行预加工处理的函数方法,当我们需要对原始数据进行一个处理时,我们就需要用到getter,1
2
3
4
5
6
7
8
9
10
11
12
13
14const store = new Vuex.Store({
state: {
todoList: [
{ time: 1, text: 'do some'},
{ time: 2, text: 'do some' }
]
},
getters: {
//这里我们返回数据的长度
dealTodo: state => {
return state.todoList.length
}
}
})
Getter 会暴露为 store.getters 对象,我们可以以属性的形式访问这些值:1
2//使用
this.$store.getters.dealTodo
mapGetters 辅助函数
当getters里面对象过多时,我们可以以ES6的语法形式解析里面的对象,mapGetters 辅助函数仅仅是将 store 中的 getter 映射到局部计算属性computed:
1 | import { mapGetters } from 'vuex' |
当然我们也可以使用对象的形式放入1
2
3mapGetters({
dataCount: 'getters1'
})
(三) Mutations
Mutations是更改 Vuex 的 store 中的状态的唯一方法,且不能用于处理异步事件,其中第一个参数是state, 第二参数是payload, 也就是传入数据1
2
3
4
5
6
7
8
9
10
11
12//实例
const store = new Vuex.Store({
state: {
count: 1
},
mutations: {
increment (state,payload) {
// 变更状态
state.count += payload.amount
}
}
})
此时我们不能直接调用store里面的mutations实例方法,而是要通过commit方式对应的type来触发该方法1
2
3
4
5
6
7
8
9
10//使用
//方式1
this.$store.commit('increment',{amount:100})
//方式2 直接使用包含 type 属性的对象
this.$store.commit({
type: 'increment',
amount: 10
})
Mutation 必须是同步函数,再次强调一下,所以存在异步操作的函数最好不要使用mutation里面的方法
mapMutations辅助函数
mapMutations 辅助函数将组件中的 methods 映射为 store.commit 调用(需要在根节点注入 store)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18import { mapMutations } from 'vuex'
export default {
methods: {
//方式1
...mapMutations([
'increment', // 将 `this.increment()` 映射为 `this.$store.commit('increment')`
// `mapMutations` 也支持载荷:
'incrementBy' // 将 `this.incrementBy(amount)` 映射为 `this.$store.commit('incrementBy', amount)`
]),
//方式2
...mapMutations({
add: 'increment' // 将 `this.add()` 映射为 `this.$store.commit('increment')`
})
}
}
(四) Action
action 类似于 mutation,不同在于:
- action 提交的是 mutation,而不是直接变更状态。
- action 可以包含任意异步操作。
- actions中的回调函数的第一个参数是context, 是一个与store实例具有相同属性和方法的对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment (state) {
state.count++
}
},
actions: {
//写法1
increment (context) {
context.commit('increment')
},
//写法2 我们也可以使用ES6语法
increment ({state,commit}) {
commit('increment')
}
}
})
action的触发,当然action也和mutation的触发方式差不多,也同样支持包含 type 属性的对象方式分发,下面我们就简单写一种,当然关键字不一样,这个触发关键字是dispatch1
this.$store.dispatch('increment',data)
在上面我们也说到action可以进行异步操作,那么我们就可以以promise为例简单实现一下1
2
3
4
5
6
7
8
9
10
11const store = {
//...
actions:{
increment({commit},data){
return new Promise((resolve)=>{
commit('increment',data)
resolve()
})
}
}
}
mapActions辅助函数
mapActions 辅助函数将组件中的 methods 映射为 store.dispatch 调用(需要在根节点注入 store)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19import { mapActions } from 'vuex'
export default {
// ...
methods: {
...mapActions([
// 将 `this.increment()` 映射为 `this.$store.dispatch('increment')`
'increment',
// `mapActions` 也支持载荷:
// 将 `this.incrementBy(amount)` 映射为 `this.$store.dispatch('incrementBy', amount)`
'incrementBy'
]),
...mapActions({
// 将 `this.add()` 映射为 `this.$store.dispatch('increment')`
add: 'increment'
})
}
}
vuex项目结构拆分
当项目store文件很大的时候,我们就不得不拆分项目的目录结构,大体上我们必须准守以下规则
- 应用层级的状态应该集中到单个 store 对象中。
- 提交 mutation 是更改状态的唯一方法,并且这个过程是同步的。
- 异步逻辑都应该封装到 action 里面。
只要遵循上面的规则,代码可以任意组织,下面是我经常性使用的组合形式1
2
3
4
5
6
7
8
9
10
11└── store
├── index.js
├── Type.js
├── binding
│ ├── actions.js
│ ├── index.js
│ └── mutations.js
├── house
├── actions.js
├── index.js
└── mutations.js
store的根目录index.js用于整合各个局部状态store,使用modules整合1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16//文件 store/index.js
import Vuex from 'vuex'
import Vue from 'vue'
import houseStore from './house'
import bindingStore from './binding'
Vue.use(Vuex)
const store = new Vuex.Store({
modules:{
house:houseStore, //house store
binding:bindingStore //binding store
}
})
export default store
Type.js主要用于存储事件type名1
2
3
4
5
6//Type.js
//例如...
//操作1
export const RRDUCELIST = 'RRDUCELIST'
//操作2
export const ADDLIST = 'ADDLIST'
局部store我就以binding为例子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
41
42
43
44
45
46
47
48
49
/*----------------------------index.js-----------------------------*/
//index.js
import {RRDUCELIST} from '@/store/Type.js'
import mutations from './mutations'
import actions from './actions'
const index = {
state:{
tableDta:[
{data:['数据1','数据2','数据3']},
]
},
mutations,
actions,
}
export default index
/*----------------------------mutations.js-----------------------------*/
//mutations
import {RRDUCELIST,ADDLIST} from '@/store/Type.js'
const mutations = {
//删除数据
[RRDUCELIST](state, payload) {
state.tableDta.splice(0, 1)
},
//增加数据
[ADDLIST](state,payload){
state.tableDta.push(payload)
}
}
export default mutations
/*----------------------------actions.js-----------------------------*/
//actions
import {RRDUCELIST,ADDLIST} from '@/store/Type.js'
const actions = {
reduceListAction({commit,state},index){
return new Promise((resolve, reject) => {
commit(RRDUCELIST,index)
resolve()
})
},
addListAction({state,commit},data){
commit(ADDLIST,data)
}
}
export default actions