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 }