主要实现
- vuex也是一个插件
- 实现四个东西:state/mutations/actions/getters
- 创建Store
- 数据响应式(基于vue)
那么接下来就开始写代码咯
iVuex.js
let Vue;
class Store {
constructor(options){
this.state = new Vue({
data: options.state
});
this.mutations = options.mutations;
this.actions = options.actions;
options.getters && this.handleGetters(options.getters)
}
// 因为commit 要做提交更新数据操作,会有作用域问题,所以用箭头函数,让 commit 一直指向 Store
// 注意这里用箭头函数形式,后面actions实现时会有作用
commit = (type, arg) => {
this.mutations[type](this.state, arg);
};
dispatch(type, arg) {
this.actions[type]({
commit: this.commit,
state: this.state
}, arg);
}
handleGetters(getters) {
// 定义this.getters
this.getters = {};
// 遍历getters选项,为this.getters定义property
// 属性名就是选项中的key,只需定义get函数保证其只读性
Object.keys(getters).forEach(key => {
// defineProperty 给对象指定一个属性(可以控制只读)
Object.defineProperty(this.getters, key, {
// 在这里就是给 this.getters 对象指定若干属性 key,内容是 {}
// 里面有一个 get 函数(只读)
get: () => { // 注意依然是箭头函数
return getters[key](this.state); // 这就是调用传进来到函数
}
});
});
}
}
function install(_Vue) {
// 这样store执行的时候,就有了Vue,不用import
// 这也是为啥Vue.use必须在新建store之前
Vue = _Vue;
// 混入
Vue.mixin({
beforeCreate() {
// 这样才能获取到传递进来的store
// 只有root元素才有store,所以判断一下
if(this.$options.store){
Vue.prototype.$store = this.$options.store;
}
}
})
}
export default { Store, install}
好了接下来试试到底行不行呢?
iStore.js
import Vue from 'vue'
import Vuex from './iVuex'
Vue.use(Vuex);
export default new Vuex.Store({
state: {
count: 0
},
mutations: {
increment(state, n = 1) {
state.count += n;
}
},
// 派生属性
getters: {
score(state) {
return `共扔出:${state.count}`;
}
},
actions: {
incrementAsync({ commit }) {
setTimeout(() => {
commit("increment", 5);
}, 1000)
// dispatch("....")
}
}
});
main.js
import store from './iStore'
Home.vue
<template>
<div id="app">
<div>冲啊,手榴弹扔了{{$store.state.count}}个</div>
<button @click="addAsync">蓄力扔俩</button>
</div>
</template>
<script>
export default {
methods: {
addAsync() {
this.$store.dispatch("incrementAsync");
}
}
};
</script>