这里我们实现一个简单的Vuex,Vuex的基础知识不再赘述,参见官网 。Demo源代码参见:Github
一、要实现的一个简单的小例子
目标:实现state(初始值 count: 0, msg: 'Hello World'
)、getters(翻转 msg 的方法)、mutations(给 count 增加2的方法)、actions(给 count 增加5的方法),其他功能本次不实现
store/index.js
中:
import Vue from 'vue'
import Vuex from 'Vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
count: 0,
msg: 'Hello World'
},
getters: {
reverseMsg (state) {
return state.msg.split('').reverse().join('')
}
},
mutations: {
increate (state, payload) {
state.count += payload
}
},
actions: {
increateAsync (context, payload) {
setTimeout(() => {
context.commit('increate', payload)
}, 2000)
}
}
})
二、分析 Vuex 的基本结构
从上面的代码可以看出导入的 Vuex,需要以下两部分组成
1、 Vue.use(Vuex)
=> 要有一个 install 方法
2、 new Vuex.Store({ xxx })
=> 要有一个 Store 类
三、实现 install 方法
首先需要定义一个_Vue
接收当前创建的Vue
实例,然后通过混入在 beforeCreate
钩子中,判断当前实例选项中是否有store属性。如果是组件实例,不存在store属性;如果是Vue
实例,将实例选项中的store挂载到_Vue
的原型对象中的$store上面
let _Vue = null
function install (Vue) {
_Vue = Vue
_Vue.mixin({
beforeCreate () {
if (this.$options.store) {
_Vue.prototype.$store = this.$options.store
}
}
})
}
四、实现 Store 类
1、在构造器中,将创建Store对象时传入选项中的state、getters、mutations、actions都赋给当前对象实例,注意这里需要将state、getters转换为响应式的
2、实现 commit 方法
3、实现 actions 方法
具体代码实现:
class Store {
constructor (options) {
// 如果选项中没有传入给默认值为空对象
const {
state = {},
getters = {},
mutations = {},
actions = {}
} = options
// 将 state 转换为响应式的
this.state = _Vue.observable(state)
this.getters = Object.create(null)
Object.keys(getters).forEach(key => {
// 给 getters 中的每一个方法设置为响应式的
Object.defineProperty(this.getters, key, {
get: () => getters[key](state)
})
})
this._mutations = mutations
this._actions = actions
}
commit (key, payload) {
this._mutations[key](this.state, payload)
}
dispatch (key, payload) {
this._actions[key](this, payload)
}
}
五、导出
export default {
install,
Store
}