掌握工作中Vuex核心API用法以及基本原理
Vuex是什么
Vuex是Vue的状态管理工具,为了更方便实现多个组件共享状态。
Vuex的特点:
Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。
你不能直接改变 store 中的状态。改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation。这样使得我们可以方便地跟踪每一个状态的变化,从而让我们能够实现一些工具帮助我们更好地了解我们的应用。
Vuex核心功能点
我们使用Vue脚手架创建一个项目作为本次演练的开发环境。
vue create vuex-demo
复制代码
注意:生成项目的时候,记得选中vuex,避免后面手动安装vuex并导入到main.js中。
State
第一步:在仓库store中定义需要全局共享的state变量
state: {
age: 25
}
复制代码
第二步:在对应的组件中获取并显示在页面上
<p>{{$store.state.age}}</p>
复制代码
Getters
getters相当于组件中的computed计算属性。当state中定义的数据发送变化后,getters中的数据会自动跟着变化。
第一步:在仓库store中定义好getters
getters: {
getAge(state) {
return state.age + 1;
}
}
复制代码
第二步:在对应的组件中获取并显示在页面上
<p>{{$store.getters.getAge}}</p>
复制代码
Mutations
第一步:在仓库store中定义需求调用的mutation方法
mutations: {
incre(state, payload) {
state.age += payload.age;
}
}
复制代码
注意:参数payload可以是对象。
第二步:在对应组件中定义触发更改状态的模板和方法
// template
<button @click="add">增加</button>
// script
methods: {
add() {
this.$store.commit('incre', {age: 1});
}
}
复制代码
注意:'incre’名称一定要和mutations中定义的名称一样。
Actions
第一步:在仓库store中定义需求调用的mutation方法
actions: {
increAsyn({commit}, payload) {
commit('incre', payload);
}
}
复制代码
第二步:在对应组件中定义触发更改状态的模板和方法
// template
<button @click="addAsyn">异步增加</button>
// script
addAsyn() {
this.$store.dispatch('increAsyn', {age: 1});
}
复制代码
注意:mutations 必须是同步函数,actions可以为异步函数。
Modules
第一步:在仓库store中定义不同的模块以及modules方法
const moduleA = {
state: {
name: 'txm',
age: 25
},
getters: {},
mutations: {},
actions: {}
}
const moduleB = {
state: {
name: 'sxm',
age: 22
},
getters: {},
mutations: {},
actions: {}
}
modules: {
a: moduleA,
b: moduleB
}
复制代码
第二步:在对应的组件中获取并显示在页面上
<p>{{$store.state.a.age}}</p>
<p>{{$store.state.b.age}}</p>
复制代码
辅助函数的使用
mapState
第一步:在对应的组件中从vuex取出mapState
import {mapState} from 'vuex';
复制代码
若计算属性只为获取仓库store的状态,则可以使用以上方式:
computed: mapState([
'age'
])
复制代码
若即想获取仓库store里的状态又可以自定义组件的计算属性,则可以使用以上方式:
computed: {
...mapState([
'age'
])
}
复制代码
第二步:在对应的组件中获取并显示在页面上
<p>{{age}}</p>
复制代码
mapGetters
第一步:在对应的组件中从vuex取出mapGetters
import {mapGetters} from 'vuex';
复制代码
通过组件中的计算属性进行获取:
computed: {
...mapGetters([
'getAge'
])
}
复制代码
第二步:在对应的组件中获取并显示在页面上
<p>{{getAge}}</p>
复制代码
mapMutations
第一步:在对应的组件中从vuex取出mapMutations
import {mapMutations} from 'vuex';
复制代码
在组件的methods属性中获取仓库store中的mutations方法,然后在methods里对应的方法中执行也可以携带参数。
methods: {
add() {
// this.$store.commit('incre', {age: 1});
this.incre({age: 1});
},
...mapMutations([
'incre'
])
}
复制代码
第二步:在对应组件中点击页面按钮看见状态的变化。
mapActions
第一步:在对应的组件中从vuex取出mapActions
import {mapActions} from 'vuex';
复制代码
在组件的methods属性中获取仓库store中的actions方法,然后在methods里对应的方法中执行也可以携带参数。
methods: {
addAsyn() {
// this.$store.dispatch('increAsyn', {age: 1});
this.increAsyn({age: 1});
},
...mapActions([
'increAsyn'
])
}
复制代码
实现简易的Vuex
由于Vue插件的限制,插件必须提供一个install方法,所以需要暴露一个install方法出去。在该方法中使用mixin结合beforeCreate钩子函数让所有组件都拥有$store属性。
let Vue;
class Store {
constructor(options = {}) {
this.vm = new Vue({
data: {
state: options.state
}
})
let getters = options.getters;
this.getters = {}
Object.keys(getters).forEach(getterName => {
Object.defineProperty(this.getters, getterName, {
get: () => {
return getters[getterName](this.state)
}
})
})
let mutations = options.mutations || {}
this.mutations = {}
Object.keys(mutations).forEach(mutaitonName => {
this.mutations[mutaitonName] = payload => {
mutations[mutaitonName](this.state, payload);
}
})
let actions = options.actions || {}
this.actions = {}
Object.keys(actions).forEach(actionName => {
this.actions[actionName] = payload => {
actions[actionName](this, payload);
}
})
}
commit = (method, payload) => {
this.mutations[method](payload);
}
dispatch(method, payload) {
this.actions[method](payload)
}
get state() {
return this.vm.state
}
}
const install = (_Vue) => {
Vue = _Vue;
Vue.mixin({
beforeCreate() {
if(this.$options && this.$options.store) {
// 给根实例增加$store属性
this.$store = this.$options.store
} else {
// 有可能单独创建了一个实例没有父亲,那就无法获取到store属性
this.$store = this.$parent && this.$parent.$store
}
}
})
}
export default {
install,
Store
}
复制代码
注意:在实现commit方法时,会存在this指向问题,我们采用箭头函数即可。
总结
上面主要是本人复习简易整理的Vuex的核心用法,方便日后查看,简易有需要的小伙伴和把实现简易的Vuex这小节认值敲几遍。
最后