手撕VUE源碼(二):vuex的底層實現


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
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM