Vuex粗解
Vuex定义
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。
说得直白点,vuex就是vue.js中管理数据状态的一个库,通过创建一个集中的数据存储,供程序中所有组件访问。
一个数据只要放在了vuex中,当前项目所有的组件都可以直接访问这个数据。
每一个 Vuex 应用的核心就是 store(仓库)。“store”基本上就是一个容器,它包含着你的应用中大部分的状态 (state)。Vuex 和单纯的全局对象有以下两点不同:
vuex有以下常用的几个核心属性概念:
- State
- Getters
- Mutations
- Actions
- Modules
一.State 单一状态树
vuex中的state类似于data,用于存放数据,只不过这个数据是所有组件公用的。
定义
export default new Vuex.Store({
state: {
num: 0 // 定义了一个num
}})
组件中调用:
<template>
<h3>{{$store.state.num}}</h3>
</template>
简化调用:
<h3>{{num}}</h3>
但是调用state时需要在computed写下相关的定义
computed: {
num(){
return this.$store.state.num
}}
二,Getters 计算属性
vuex中的getters类似于computed计算属性,getters的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。
人话:保存数据,并且可以使用State中的数据进行运算
定义
export default new Vuex.Store({
state: {num: 2},
getters: {
// 这里的参数state可以让我们快速获取到仓库中的数据
doubleNum(state) {
return state.num * 2;
}}
})
组件中调用:
<template>
<h3>{{$store.getters.doubleNum}}</h3>
</template>
//同样也可以使用简化写法,类似于State
三,Mutations 同步修改数据方法
人话:用于保存同步修改数据的一些方法
export default new Vuex.Store({
state: {
num: 2
},
mutations: {
// payload专业名称为“载荷”,其实就是个参数
addNum(state, payload) {
state.num += payload;
}}
})
组件中
export default {
methods: {
btnClick(){
// 使用commit来触发事件,第二个参数是要传递给payload的数据
this.$store.commit('addNum', 2)
}
}};
四,Actions 异步修改数据方法
人话:保存异步修改数据的一些方法
export default new Vuex.Store({
state: {
num: 2
},
mutations: {
addNum(state, payload) {
state.num += payload;
}},
actions: {
// context是一个对象,包含了commit和state
AsyncAddNum(context,payload) {
setTimeout(() => {
context.commit('addNum', payload)
}, 1000)
}}})
组件中:
<template>
<div>
<h3>{{$store.state.num}}</h3>
<button @click="btnClick">累加2</button>
</div>
</template>
<script>
export default {
methods: {
btnClick(){
// dispatch是分发到意思,其实也是触发Actions中的方法
this.$store.dispatch('AsyncAddNum', 2)
}}};
</script>
五.辅助函数
获取单个数据或触发某个方法比较容易,我们直接拿到和触发就行,但如果要获取的数据和触发的方法很多很多个,我们获取与调用起来就比较麻烦了,这时候我们需要借用辅助函数。
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
num: 2, //基础数值
title: '标题'
},
getters: {
doubleNum(state) { //双倍数值
return state.num * 1;
}},
mutations: {
addNum(state, payload) { //增加数值
state.num += payload;
},
cutNum(state, payload) { //减去数值
state.num -= payload;
}},
actions: {
AsyncAddNum({ commit },payload) { //延迟增加数值
setTimeout(() => {
commit('addNum', payload)
}, 300)},
AsyncCutNum({ commit }, payload) { //延迟减去数值
setTimeout(() => {
commit('cutNum', payload)
}, 300)}
}})
此时,要拿到num和title的话,我们可以在组件中:
<template>
<div>
<h2>{{title}}</h2>
<h3>{{num}}</h3>
</div>
</template>
<script>
// 引入辅助函数mapState
import {mapState} from 'vuex' //引入辅助函数
export default {
// 在computed中引用
computed: {
...mapState(['title', 'num']) //引入数据
}
};
</script>
如果打算从getters中取出num:
<h3>{{doubleNum}}</h3>
<script>
import {mapState, mapGetters} from 'vuex' //引入辅助函数
export default {
computed: {
...mapState(['title']), //引入数据
...mapGetters(['doubleNum']) //引入方法
}
};
</script>
如果打算把mutations和actions中的方法引入:
<template>
<div>
<h2>{{title}}</h2>
<h3>{{doubleNum}}</h3>
<button @click="addNum(2)">累加2</button>
<button @click="AsyncCutNum(2)">递减2</button>
</div>
</template>
<script>
import {mapState, mapGetters, mapMutations, mapActions} from 'vuex'
methods: {
// 这里负责引入,我们把引入后的事件直接写在标签上,顺便把参数也带上
...mapMutations(['addNum']),
...mapActions(['AsyncCutNum'])
}
</script>
如果你必须把点击事件写在methods中,而不是标签上的话,你也可以这样:
<template>
<div>
<button @click="btnClick1">累加2</button>
<button @click="btnClick2">递减2</button>
</div>
</template>
<script>
import {mapState, mapGetters, mapMutations, mapActions} from 'vuex'
export default {
methods: {
...mapMutations(['addNum']), //同步处理函数
...mapActions(['AsyncCutNum']), //异步处理函数
btnClick1(){
// 直接通过this.xxx来调用辅助函数引入的事件
this.addNum(2) }, //使用函数中的方法
btnClick2(){
this.AsyncCutNum(2) }} //使用函数中的方法
};
</script>
六、Module 拆分模块
因为不同的函数可以单独抽调出来做成不同的模块,放入不同的文件夹,模块化后使得维护的打理更加迅速与高效
store下最大的index.js:
export default {
state: {
num: 2
},
getters: {
doubleNum(state) {
return state.num * 1;
}
},
mutations: {
addNum(state, payload) {
state.num += payload;
}
},
actions: {
AsyncAddNum({ commit }, payload) {
setTimeout(() => {
commit('addNum', payload)
}, 300)
}
modules: { //仓库函数
}
}
那么就把 addNum(state, payload)这个函数分出去放到add这个文件夹
store下最大的index.js:
import addNum from './add' //引入addNum这个函数从 add这个文件夹中
export default new Vuex.Store({
state: {
num: 2
},
getters: {
doubleNum(state) {
return state.num * 1;
}
}, //可以看到此处已经没有mutations的存在了
actions: {
AsyncAddNum({ commit }, payload) {
setTimeout(() => {
commit('addNum', payload)
}, 300)}
modules: {
addNum //此处来调用addNum使得他可以被组件中被使用
}})
store下add这个文件夹的index.js:
export default {
namespaced: true, //命名空间,为true时,可以在store中把当前模块文件夹名称(add),当作模块名使用 命名空间的存在,人话:使得store中的其他文件夹的index.js能和总index,js产生关联,十分重要
state: {},
getters: {},
mutations: {
addNum(state, payload) {
state.num += payload;
}},
actions: {},
}
七、拆分写法
实际上我们可以把state、getter、mutation、action和module全部都从store下的index.js中抽离出来,这样可以让store文件看着更加简洁。我们来将 store/index.js
进行拆分:
state.js
:
export default {
num1: 0,
title: '标题'
}
mutations.js
:
export default {
cutNum(state, payload) {
state.num1 -= payload;
}
}
actions.js
:
export default {
AsyncCutNum({ commit }, payload) {
setTimeout(() => {
commit('cutNum', payload)
}, 300)
}
}
modules.js
:
import add from './add'
export default {
add
}
最后,在 store/index.js
中:
import Vue from 'vue'
import Vuex from 'vuex'
import state from './state' //同级的js文件 state.js
import mutations from './mutations' //同级的js文件 mutations.js
import actions from './actions' //同级的js文件 actions.js
import modules from './modules' //同级的js文件 modules.js
Vue.use(Vuex)
export default new Vuex.Store({
state,
mutations,
actions,
modules
})