vuex的实现
源代码可以查看我的github: https://github.com/Jasonwang911/TryHardEveryDay/tree/master/Vuex/vuex-resouce 欢迎star
先描述一下vuex的使用:
store.js
import Vue from "vue";
import Vuex from "./vuex/myVuex";
Vue.use(Vuex);
export default new Vuex.Store({
state: {
age: 20
},
getters: {
// date 的 computed
myAge(state) {
return state.age + 10;
}
},
mutations: {
syncAdd(state, payload) {
state.age += payload;
},
syncMinuts(state, payload) {
state.age -= payload;
}
},
actions: {
asyncMinus({ commit }, payload) {
setTimeout(() => {
commit("syncMinuts", payload);
}, 1000);
}
}
});
main.js中引用:
import Vue from "vue";
import App from "./App.vue";
import router from "./router";
import store from "./store";
Vue.config.productionTip = false;
new Vue({
router,
store, // 在每个实例上添加一个 $store 对象
render: h => h(App)
}).$mount("#app");
先说这两点
1. Store是一个类
2. Vue.use(Vuex);
首先建立一个类并导出,同时导出一个install的方法,这个方法接收一个参数 _Vue,即 vue实例
let Vue
class Store {
}
const install = _Vue => {
Vue = _Vue
}
export default {
Store,
install
}
然后再main.js 中所作的就是讲store实例注册到vue的跟组件和所有的子组件上, 这里使用了Vue.mixin()的方法,在每个组件中注入$store,并在子组件中通过 this.$parents来拿到父组件的$store并添加到子组件的实例上
const install = _Vue => {
Vue = _Vue;
// console.log(Vue);
Vue.mixin({
beforeCreate() {
if (this.$options && this.$options.store) {
// 根组件
this.$store = this.$options.store;
} else {
this.$store = this.$parent && this.$parent.$store;
}
}
});
};
先来看看state是怎么用的
import Vue from "vue";
import Vuex from "./vuex/myVuex";
Vue.use(Vuex);
export default new Vuex.Store({
state: {
age: 20
},
});
在new Vuex.Store的实例的时候传入了一个对象,这个对象options
然后我们添加state的这个属性
class Store { constructor(options) { // options 是 new Vuex时注入的对象 this._vm = options.state || {}; } get state() { // store.state return this._vm; } }
这里有一个问题,通过options获取的state并不是Observe状态的,并不能响应式的更新视图,如何做才能使state变成响应式的并触发视图的更新呢,也就是通过Vue的数据劫持进行包装转换,
这里通过new Vue,并把state放入创建的Vue的data中来实现这个操作
class Store {
constructor(options) {
// options 是 new Vuex时注入的对象
this._vm = new Vue({
data: {
state: options.state
}
});
}
get state() {
// store.state
return this._vm.state;
}
}
这样,$store.state就变成了响应式的状态了
接下来,同理 getters,mutations, actions 也是通过options传入获取的
import Vue from "vue";
import Vuex from "./vuex/myVuex";
Vue.use(Vuex);
export default new Vuex.Store({
state: {
age: 20
},
getters: {
// date 的 computed
myAge(state) {
return state.age + 10;
}
},
mutations: {
syncAdd(state, payload) {
state.age += payload;
},
syncMinuts(state, payload) {
state.age -= payload;
}
},
actions: {
asyncMinus({ commit }, payload) {
setTimeout(() => {
commit("syncMinuts", payload);
}, 1000);
}
}
});
先来实现一下getters方法: 每一个getter方法其实都是getters的一个属性,但是这个属性返回了一个函数。属性可以返回函数的方法可以通过Object.definedProperty()中的get()来实现:
class Store {
constructor(options) {
// options 是 new Vuex.Store时注入的对象
// getters 拿到new Store的时候传入的getters
let getters = options.getters || {};
// 创建 Store 的 getters 属性
this.getters = {};
Object.keys(getters).forEach(getterName => {
// 是个函数,但是返回的是个属性
Object.defineProperty(this.getters, getterName, {
get() {
return getters[getterName](this.state);
}
});
});
}
}
这里其实只做了一件事情: 循环传入的options上的getters对象,并在用户调用getters中的每一个属性的时候返回一个getter函数并执行,
同理,mutations和actions也是如此实现的,只不过各自多了一个commit和dispatch的方法。
commit 和 dispatch 方法的原理就是通过参数type去对应的mutations和actions中查找对应的mutation或者action传入payload并执行
dispatch = (type, payload) => {
this.actions[type](payload);
};
commit = (type, payload) => {
this.mutations[type](payload);
};
查看Vuex源码,作者巧妙的将这个通过对象key进行循环的方法封装成了一个forEach函数:
const forEach = (obj, callback) => {
Object.keys(obj).forEach(key => {
callback(key, obj[key]);
});
};
这个函数传入了一个对象和一个回调函数,通过对key的循环,执行了回调函数,并向回调函数中传入了循环出对象obj的key和value,整理后整个Store对象变成了如下:
const forEach = (obj, callback) => {
Object.keys(obj).forEach(key => {
callback(key, obj[key]);
});
};
class Store {
constructor(options) {
// options 是 new Vuex时注入的对象
// this._s = options.state || {};
// 将store中的状态变成可被观测的数据
this._vm = new Vue({
data: {
state: options.state
}
});
// getters 拿到new Store的时候传入的getters
let getters = options.getters || {};
// 创建 Store 的 getters 属性
this.getters = {};
forEach(getters, (getterName, fn) => {
Object.defineProperty(this.getters, getterName, {
get: () => {
return fn(this.state);
}
});
});
// mutations
let mutations = options.mutations || {};
this.mutations = {};
forEach(mutations, (mutationName, fn) => {
this.mutations[mutationName] = payload => {
fn(this.state, payload);
};
});
// actions
let actions = options.actions || {};
this.actions = {};
forEach(actions, (actionName, fn) => {
this.actions[actionName] = payload => {
fn(this, payload);
};
});
}
dispatch = (type, payload) => {
this.actions[type](payload);
};
commit = (type, payload) => {
this.mutations[type](payload);
};
get state() {
return this._vm.state;
}
}
以上基本实现了一个简单的vuex的基本流程,所有的源码可以在我的github上查看,后续会继续修改支持vuex的模块化。

浙公网安备 33010602011771号