前言
Vuex集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以可预测的方式发生变化。
核心概念
-
State状态 数据 保存应用的状态
export default new Vuex.Store({ state: { count: 0 } }) -
Mutations 更改状态的函数 用于修改状态
export default new Vuex.Store({ mutations: { add(state) { state.count++ } } }) -
Getters 类似计算属性
export default Vuex.Store({ getters: { doubleCount(state) { return state.count * 2 } } }) -
Actions 异步操作 添加业务逻辑
export default new Vuex.Store({ actions: { add({ commit }) { setTimeout(() => { commit('add') }, 1000) } } }) -
store包含以上概念的容器
需求分析
- State的数据响应式
- Getters只读的state
- Actions可以获取commit. state, dispatch等方法
- Mutations可以获取state进行数据变更
任务
-
实现一个插件
-
实现Store类
- 维持一个响应式状态的state
- 实现commit
- 实现dispatch
- 实现getters
-
实现install方法
- 注册全局方法$store
-
实现
-
实现Store类, install方法并注册全局$store方法
类要想实现插件需要内部有install方法
// 引用构造函数,一会注册方法 let Vue class Store { } // 实现install方法 function install(_Vue) { Vue = _Vue // 为什么要⽤混⼊⽅式写?主要原因是use代码在前,Store实例创建在后,⽽install逻辑⼜需要⽤到该实例 Vue.mixin({ beforeCreate() { if (this.$options.store) { Vue.prototype.$store = this.$options.store } }, }) } // 注:Store的使用的方法是Vuex.Store,所以包一层 export default { Store, install } -
保存用户配置
// 在Store类中保存配置 class Store { constructor(options) { this._mutations = options.mutations || {} this._actions = options.actions || {} this._wapperGetter = options.getters || {} } } -
实现state响应式,并限制外部只读不可更改
class Store { constructor(options) { // 实现响应式 this._vm = new Vue({ data: { // 设置$$state为了防止外部直接访问 $$state: options.state, } }) } get state() { // 可以从Vue实例中的_data中取到响应式的$$state return this._vm._data.$$state } set state(v) { // 修改抛出错误 console.error('please use replaceState to reset state') } } -
实现commit方法, dispatch方法
class Store { constructor(options) { this._mutations = options.mutations || {} this._actions = options.actions || {} this._wapperGetter = options.getters || {} // 绑定this,如果在setTimeout中使用this指向就有问题 this.commit = this.commit.bind(this) this.dispatch = this.dispatch.bind(this) } // commit方法 commit(type, payload) { const entry = this._mutations[type] if (entry) entry(this.state, payload) } // dispatch方法 dispatch(type, payload) { const entry = this._actions[type] if (entry) entry(this, payload) } } -
实现getters方法
class Store { constructor(options) { this._wapperGetter = options.getters || {} // getters const computed = {} this.getters = {} const store = this Object.keys(this._wapperGetter).forEach((key) => { const fn = this._wapperGetter[key] // 同名方法执行函数并传入state computed[key] = function() { return fn(store.state) } // 给getters判断只读的属性 Object.defineProperty(store.getters, key, { get: () => store._vm[key], }) }) // 实现响应式 this._vm = new Vue({ data: { // 设置$$state为了防止外部直接访问 $$state: options.state, }, computed }) } }
最终实现代码
let Vue
// 实现Store类
class Store {
constructor(options) {
// 保存用户配置
this._mutations = options.mutations || {}
this._actions = options.actions || {}
this._wapperGetter = options.getters || {}
// 定义计算属性
const computed = {}
this.getters = {}
// 绑定this
const store = this
Object.keys(this._wapperGetter).forEach((key) => {
const fn = this._wapperGetter[key]
// 同名方法执行函数并传入state
computed[key] = function() {
return fn(store.state)
}
// 给getters判断只读的属性
Object.defineProperty(store.getters, key, {
get: () => store._vm[key],
})
})
// 实现响应式
this._vm = new Vue({
data: {
$$state: options.state,
},
computed,
})
this.commit = this.commit.bind(this)
this.dispatch = this.dispatch.bind(this)
}
get state() {
return this._vm._data.$$state
}
set state(v) {
console.error('please use replaceState to reset state')
}
commit(type, payload) {
const entry = this._mutations[type]
if (entry) entry(this.state, payload)
}
dispatch(type, payload) {
const entry = this._actions[type]
if (entry) entry(this, payload)
}
}
// 实现插件
function install(_Vue) {
Vue = _Vue
Vue.mixin({
beforeCreate() {
if (this.$options.store) {
Vue.prototype.$store = this.$options.store
}
},
})
}
export default { Store, install }
结语
- state的值经过Vue进行响应式处理,并限制外部不可更改状态。
- commit, dispatch在配置找到方法并执行,执行的时候传入需要的值。
- getters使用Object.defineProperty添加只读属性。
- Vuex使用Vue中的响应式数据,所在它是和Vue强耦合的,这也就是只能在Vue中使用的原因。