前言
用vuex也有一段时间了,今天手撸一个简易的vuex。
1.install
vue暴露的插件系统,使用Vue.use()时必须提供一个install函数注入Vue
`//声明一个全居变亮保存Vue
let Vue = null;
const install = _Vue => {
Vue = _Vue;
Vue.mixin({
//注册一个全局混入的beforeCreate
beforeCreate() {
const options = this.$options;
const { store } = options;
if (store) {
//当前组件存在store则直接赋值
this.$store = typeof store === 'function' ? store() : store;
} else if (options.parent && options.parent.$store) {
//子组件从父组件拿$store
this.$store = options.parent.$store;
}
},
});
};`
2. store
//准备一个简易的store类
const store = function(options) {
const { state = {}, mutations = {}, actions = {}, getters = {} } = options || {};
//使用Object.create(null)创建一个纯净的对象,传null的话没有__proto__
//借助已保存的Vue的observable方法将state转化为响应式对象
this.state = Vue.observable(state);
this.mutations = Object.create(null);
this.actions = Object.create(null);
this.getters = Object.create(null);
//使用箭头函数,绑定this方便解构使用
this.dispath = () => {};
this.commit = () => {};
//modules待补
};
3. mutations
//遍历传入的mutations
Object.keys(mutations).forEach(mutation => {
//使用...接收所有参数,mutations第一个参数固定为state
this.mutations[mutation] = (...params) => {
mutations[mutation](this.state, ...params);
};
});
4. actions
//遍历传入的actions
Object.keys(actions).forEach(action => {
//使用...接收所有参数,actions需要使用commit提交第一个参数固定为当前实例
this.actions[action] = (...params) => {
//返回调用结果方便移步操作
return actions[action](this, ...params);
};
});
5. getters
//遍历传入的getters
Object.keys(getters).forEach(getter => {
//getters比较特殊需要做一步代理操作,第一个参数固定为state
Object.defineProperty(this.getters, getter, {
get: () => {
return getters[getter](this.state);
},
});
});
6. dispath
//dispath做一步promise包装
this.dispath = (action, ...params) => {
return new Promise(resolve => {
//取调用结果简单判断下是否为promise
const res = this.actions[action](...params);
const { then } = res || {};
if (then) {
return then.call(res, () => {
resolve();
});
}
resolve();
});
};
7. commit
//commit 提交mutation
this.commit = (mutation, ...params) => {
this.mutations[mutation](...params);
};
8. map映射辅助函数
//map传参有两种形式Array及obj,准备一个工具函数解析map传参,暂时不做module处理
const normalizeMap = params => {
switch (Object.prototype.toString.call(params)) {
case '[object Object]':
return Object.keys(params).map(key => ({ key, val: params[key] }));
case '[object Array]':
return params.map(key => ({ key, val: key }));
default:
//抛出异常
throw new Error('参数必须为数组或对象');
}
};
//mapState
const mapState = params => {
return normalizeMap(params).reduce((res, { key, val }) => {
//此处this指向组件实例
res[key] = function() {
return typeof val === 'function' ? val(this.$store.state) : this.$store.state[val];
};
return res
}, {});
};
//mapGetters
const mapGetters = params => {
return normalizeMap(params).reduce((res, { key, val }) => {
//此处this指向组件实例
res[key] = function() {
return this.$store.getters[val];
};
return res
}, {});
};
//mapActions
const mapActions = params => {
return normalizeMap(params).reduce((res, { key, val }) => {
//此处this指向组件实例
res[key] = function(...data) {
return this.$store.dispath(val, ...data);
};
return res
}, {});
};
//mapMutations
const mapMutations = params => {
return normalizeMap(params).reduce((res, { key, val }) => {
//此处this指向组件实例
res[key] = function(...data) {
this.$store.commit(val, ...data);
};
return res
}, {});
};
9. modules
待补
10. 完整代码
let Vue = null;
const install = _Vue => {
Vue = _Vue;
Vue.mixin({
//注册一个全局混入的beforeCreate
beforeCreate() {
const options = this.$options;
const { store } = options;
if (store) {
//当前组件存在store则直接赋值
this.$store = typeof store === 'function' ? store() : store;
} else if (options.parent && options.parent.$store) {
//子组件从父组件拿$store
this.$store = options.parent.$store;
}
},
});
};
//准备一个简易的store类
const store = function(options) {
const { state = {}, mutations = {}, actions = {}, getters = {} } = options || {};
//使用Object.create(null)创建一个纯净的对象,传null的话没有__proto__
//借助已保存的Vue的observable方法将state转化为响应式对象
this.state = Vue.observable(state);
this.mutations = Object.create(null);
this.actions = Object.create(null);
this.getters = Object.create(null);
//modules待补
this.modules = Object.create(null);
//遍历传入的mutations
Object.keys(mutations).forEach(mutation => {
//使用...接收所有参数,mutations第一个参数固定为state
this.mutations[mutation] = (...params) => {
mutations[mutation](this.state, ...params);
};
});
//遍历传入的actions
Object.keys(actions).forEach(action => {
//使用...接收所有参数,actions需要使用commit提交第一个参数固定为当前实例
this.actions[action] = (...params) => {
//返回调用结果方便移步操作
return actions[action](this, ...params);
};
});
//遍历传入的getters
Object.keys(getters).forEach(getter => {
//getters比较特殊需要做一步代理操作,第一个参数固定为state
Object.defineProperty(this.getters, getter, {
get: () => {
return getters[getter](this.state);
},
});
});
//使用箭头函数,绑定this方便解构使用
//dispath做一步promise包装
this.dispath = (action, ...params) => {
return new Promise(resolve => {
//取调用结果简单判断下是否为promise
const res = this.actions[action](...params);
const { then } = res || {};
if (then) {
return then.call(res, () => {
resolve();
});
}
resolve();
});
};
//commit 提交mutation
this.commit = (mutation, ...params) => {
this.mutations[mutation](...params);
};
};
//map传参有两种形式Array及obj,准备一个工具函数解析map传参,暂时不做module处理
const normalizeMap = params => {
switch (Object.prototype.toString.call(params)) {
case '[object Object]':
return Object.keys(params).map(key => ({ key, val: params[key] }));
case '[object Array]':
return params.map(key => ({ key, val: key }));
default:
//抛出异常
throw new Error('参数必须为数组或对象');
}
};
//mapState
const mapState = params => {
return normalizeMap(params).reduce((res, { key, val }) => {
//此处this指向组件实例
res[key] = function() {
return typeof val === 'function' ? val(this.$store.state) : this.$store.state[val];
};
return res;
}, {});
};
//mapGetters
const mapGetters = params => {
return normalizeMap(params).reduce((res, { key, val }) => {
//此处this指向组件实例
res[key] = function() {
return this.$store.getters[val];
};
return res;
}, {});
};
//mapActions
const mapActions = params => {
return normalizeMap(params).reduce((res, { key, val }) => {
//此处this指向组件实例
res[key] = function(...data) {
return this.$store.dispath(val, ...data);
};
return res;
}, {});
};
//mapMutations
const mapMutations = params => {
return normalizeMap(params).reduce((res, { key, val }) => {
//此处this指向组件实例
res[key] = function(...data) {
this.$store.commit(val, ...data);
};
return res;
}, {});
};
export { store, mapState, mapGetters, mapActions, mapMutations,install };