let Vue; //vue的构造函数
// modules:{
// state: 1,
// modules:{
// a:{
// state:2
// },
// b:{
// state:3
// }
// }
// }
class ModuleCollection{
constructor(options){
this.register([],options);
}
//深度优先遍历
register(path,rootModule){
//1、定义一个新的子模块
let newModule = {
_raw: rootModule,
_children: {},
state: rootModule.state
}
//2、挂载根源模块
if(path.length === 0){
this.root = rootModule
}
//6、挂载子模块,将此时遍历到的模块挂载到对应父节点上,第二遍递归时才开始走这个判断
if(path.length != 0){
//7、根据path数组,找到rootModule此时对应的父节点
let parent = path.slice(0,-1).reduce((root,current) => {
return root._children[current];
},this.root);
//8、挂载至父节点
parent._children[path[path.length - 1]] = newModule;
}
//3、查询是否有子模块
if(rootModule.modules){
//4、对子模块进行遍历
forEach(rootModule.modules,(moduleName,module) => {
//5、对子模块进行递归处理
this.register(path.concat(moduleName),module);
})
}
}
}
class Store{
//用户传入options,我们首先的任务是将options中的属性和方法,绑定到store自身作用域上
constructor(options){
//先绑定state属性
this._s = new Vue({ //给state加上数据监听,使对应视图实时响应刷新
data: {
state: options.state
}
})
new ModuleCollection(options); //数据层级整理
//getters相当于computed
let getters = options.getters || {}
this.getters = {};
//再将getters属性中的各个方法绑定到this.getters的中,执行这些方法时自动传入state
Object.keys(getters).forEach((getterName => {
Object.defineProperties(this.getters,getterName,{
//此处使用箭头函数锁定this上下文,防止因调用者变化使this变更
get:()=>{
return getters[getterName](this.state);
}
})
}))
//mutations相当于method
let mutations = options.mutations || {}
this.mutations = {};
Object.keys(mutations).forEach(mutationName => {
//将私有属性mutations的方法绑定到实例属性this.mutations上
this.mutations[mutationName] = (preload) =>{
//执行私有属性mutations上对应的方法
mutations[mutationName](this.state,preload);
}
})
}
//用户的调用入口
commit = (type,payload) => {
this.mutations[type](payload);
}
//可以通过get、set控制state存取
get state(){
return this._s
}
}
const install = (_Vue) => {
Vue = _vue;
Vue.mixin({
//声明混入对象的声明周期,在每个组件创建之前加入store
beforeCreate(){
//判断父组件还是子组件,如果是子组件则把父组件的store传给子组件
if(this.$options && this.$options.store){
this.$store = this.$options.store
}else{
this.$store = this.$parent && this.$parent.$store
}
}
})
}
export default {
install, //vue.use方法在引入模块时,默认调用模块的install方法
Store
}