需求分析
- 实现插件
- 实现Store类
- 维持一个响应式状态state
- 实现commit()
- 实现dispatch()
- getters
- 挂载$store
- 实现Store类
代码实现
1.创建src/kstore/index.js
import Vue from 'vue'
import Vuex from './kvuex.js'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
counter: 0
},
getters: {
doubleCounter(state){
return state.counter * 2
}
},
mutations: {
// state怎么来的
add(state, num = 1){
state.counter += num
}
},
actions: {
// 为什么能解构出commit? 上下文context是什么? store实例
add({ commit, dispatch, getters, state}){
setTimeout(()=>{
commit("add")
},1000)
}
},
modules: {
}
})
2.创建src/kstore/kvuex.js
// 1.实现插件
let _Vue
class Store {
constructor(options) {
this._mutations = options.mutations
this._actions = options.actions
this._wrappedGetters = options.getters
// 定义computed选项
const computed = {}
this.getters = {}
const store = this
Object.keys(this._wrappedGetters).forEach(key => {
// 获取用户定义的getter
const fn = store._wrappedGetters[key]
// 转换为computed可以使用无参数形式
computed[key] = function () {
return fn(store.state)
}
// 为getters定义只读属性
Object.defineProperty(store.getters, key, {
get: () => store._vm[key]
})
})
// 创建响应式的state
// this.$store.state.xx
this._vm = new _Vue({
data() {
return {
// 不希望被代理,就加上$或者_ vue内部隐藏属性检测
$$state: options.state
}
},
computed
})
//修改this指向
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');
}
// 修改state
// this.$store.commit('add', 1)
commit(type, payload) {
//获取type对应的mutation
const fn = this._mutations[type]
if (!fn) {
console.error('unknow mutation');
return
}
// 传入state作为参数
fn(this.state, payload)
}
dispatch(type, payload) {
//获取type对应的action
const fn = this._actions[type]
if (!fn) {
console.error('unknow action');
return
}
// 传入当前Store实例this做上下文 所以能结构出store的state/commit/dispatch/getters
return fn(this, payload)
}
}
function install(Vue) {
_Vue = Vue
Vue.mixin({
beforeCreate() {
if (this.$options.store) {
Vue.prototype.$store = this.$options.store
}
},
})
}
// 导出的对象就是Vuex
export default {
Store,
install
}
3.main.js引入 import store from './kstore'