需求
Vuex是一个帮助我们集中管理vue组件状态的状态管理插件,我们将模拟它的state、mutation、action、getter。在组件内,我们可以通过vm. s t o r e . c o m m i t ( ) 来 更 改 s t a t e , 或 者 使 用 v m . store.commit()来更改state,或者使用vm. store.commit()来更改state,或者使用vm.store.dispatch()来异步地改变state,同时阻止用户通过vm. s t o r e . s t a t e = ′ ′ 这 种 方 式 直 接 改 变 s t a t e ; 用 户 可 以 使 用 store.state=''这种方式直接改变state;用户可以使用 store.state=′′这种方式直接改变state;用户可以使用store.getters()来获取state,当state改变时,获取的值也做相应的改变。
实现
首先,我们创建一个简单的Store
- index.js
import Vue from 'vue'
import Vuex from './kstorevuex.js'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
count: 1
},
mutations: {
SET_COUNT(state, value) {
state.count = value
}
},
actions: {
ASYNC_COUNT(state, value) {
setTimeout(() => {
state.count = value
}, 2000)
}
},
getters: {
GET_COUNT(state) {
return state.count
}
}
})
和vue-router一样,我们要实现一个Store类和install方法,但是注意我们使用的时候是new Vuex.Store,所以,KVuex文件应该是这样的
- KVuex.js
let Vue
class Store {
constructor(options) {}
}
function install(_vue) {}
export default { Store, install }
同样的,我们要在install方法中将$store挂到Vue原型链上,方便组件来调用。
- function install
function install(_vue) {
// 这里和仿vue-router组件是一样的
Vue = _vue
Vue.mixin({
beforeCreate() {
if (this.$options.store) {
Vue.prototype.$store = this.$options.store
}
}
})
}
在class Store中,我们要实现getter、commit、dispatch这三个方法;和仿vue-router不同的是,我们创建响应式数据的方式有所变化,值得注意的一点是利用computed选项实现getter。
- class Store
class Store {
constructor(options) {
// 将action和mutation存入this
this._mutations = options.mutations
this._actions = options.actions
this._wrapGetters = options.getters
this.getters = {}
// 利用computed选项实现getter,避免this指向混乱,使用一个变量保存this
const store = this
let computed = {}
// 遍历vuex的getter配置项
Object.keys(store._wrapGetters).forEach(key => {
const f = store._wrapGetters[key]
// 由于computed里面的函数没有参数,所以这里稍微处理一下
computed[key] = () => {
return f(store.state)
}
// 设置store.getter只读
Object.defineProperty(store.getters, key, {
get: () => {
return store._vm[key]
}
})
})
// 创建一个响应式的$$state属性,不使用defineReactive()方法是因为实现getter方法需要使用computed选项,state前面加两个$可以不让vue自动代理$$state
this._vm = new Vue({
data: {
$$state: options.state
},
computed
})
// 将commit和dispatch从this中解构出来
const { commit, dispatch } = store
this.commit = function(type, payload) {
commit.call(store, type, payload)
}
this.dispatch = function(type, payload) {
dispatch.call(store, type, payload)
}
}
// 使用getter,返回state
get state() {
return this._vm._data.$$state
}
// 阻止用户直接修改state
set state(val) {
console.error('you can not change state by direct assignment "' + val + '"')
}
// 创建一个commit方法和dispatch方法
commit(type, payload) {
const entry = this._mutations[type]
if (!entry) {
console.error('unknown mutation type:' + type)
}
entry(this.state, payload)
}
dispatch(type, payload) {
const entry = this._actions[type]
if (!entry) {
console.error('unknown action type:' + type)
}
entry(this.state, payload)
}
}