手把手實現Vuex(一)

Vuex的定義

Vuex是一個專爲 Vue.js 應用程序開發的狀態管理模式。它採用集中式存儲管理應用的全部組件的狀態,並以相應的規則保證狀態以一種可預測的方式發生變化。主要包含以下幾個部分。bash

  • state
  • mutations
  • actions
  • getters
  • modules

Vuex 的安裝

在使用中咱們經過 Vue.use(store) 的方式實現對Vuex的安裝,而後咱們就能夠再每一個組件中使用Vuex中的方法,下面咱們看一下的它的實現。異步

  • 實現聲明一個install方法,這樣Vue.use 就能夠調用。
  • Vue.use 會傳入Vue,經過Vue.mixin 在Vue生命週期beforeCreate 爲每一個組件注入store。
//安裝的方法
const install=(_Vue)=>{
   Vue=_Vue;
  //爲每一個組件注入
  Vue.mixin({
       
        beforeCreate(){
            //說明是根
            //this.$options.store 由於在main.js 中 new Vue({store}) 
            if(this.$options && this.$options.store)
            {
                this.$store=this.$options.store;
            }
            //子組件就從父組件取
            else{
                this.$store=this.$parent && this.$parent.$store;
            }
        }
  })
}
複製代碼

state 的實現

state 是用來存儲響應式數據的單一狀態樹函數

  • state中的數據是響應式的。
  • 經過 this.$store.state 訪問其中的數據。

原理實現post

class Store{
    constructor(options)
    {
        //state 將state 數據設置爲響應式
        //this.state=options.state ||{}
        this._vm=new Vue({
              data:options.state
    }
    // 得到state 
    get state(){
       return  this._vm
    }
}
複製代碼

將數據置爲響應式有兩種方案ui

  • 直接經過 new Vue({data:XXX})。
  • 經過Vue.observable(2.6新增)。

getter 的實現

  • 調用方式:this.$store.getter.xxx,所以咱們能夠經過Object.defineProperty對xxx 屬性進行數據劫持,一旦訪問改屬性,就執行相應的方法。
const forEach=(obj,callBack)=>
{
    if(typeof obj!=='object' || obj===null)
    {
        return [];
    }
    Object.keys(obj).forEach(key=>{
          callBack(key,obj[key])
    });
}
class Store{
    constructor(options)
    {
        //state 將state 數據設置爲響應式
        //this.state=options.state ||{}
        this._vm=new Vue({
              data:options.state
        })
        //設置 getters
        let getters=options.getters ||{};
        this.getters={};
        //getter 的核心實現
        forEach(getters,(key,fn)=>{
              Object.defineProperty(this.getters,key,{
                  get:()=>{
                        return fn.call(this,this.state);
                  }
              })
        })

        })
  
    }
   
}

複製代碼

mutation的實現

mutation 都有一個字符串的 事件類型 (type) 和 一個 回調函數 (handler)。this

  • 對傳入的屬性進行遍歷訂閱
  • 經過commit方法觸發調用。

核心就是一個發佈訂閱spa

class Store{
    constructor(options)
    {
        //設置 mutations 依賴於 訂閱 發佈模式 

        let mutations=options.mutations||{};
        this.mutations={};
        forEach(mutations,(key,fn)=>{
            
             this.mutations[key]=(params)=>{
                  fn.call(this,this.state,params);
             }
        })
 
    }
   

    commit=(name,params)=>{
        this.mutations[name](params)

    }
}

複製代碼

action的實現。

本質和mutation沒有什麼不一樣,一樣也是一個發佈訂閱,就是在使用總一半用於處理異步請求。code

//
  forEach(actions,(key,fn)=>{
            this.actions[key]=(params)=>{
                fn.call(this,this.state,params);
           }
           
        })
//觸發action調用
 dispatch=(type,params)=>{
        this.actions[type](params);

    }

複製代碼

所有源碼:生命週期

class Store{
    constructor(options)
    {
        //state 將state 數據設置爲響應式
        //this.state=options.state ||{}
        this._vm=new Vue({
              data:options.state
        })
        //設置 getters
        let getters=options.getters ||{};
        this.getters={};

        forEach(getters,(key,fn)=>{
              Object.defineProperty(this.getters,key,{
                  get:()=>{
                        return fn.call(this,this.state);
                  }
              })
        })
        //設置 mutations 依賴於 訂閱 發佈模式 

        let mutations=options.mutations||{};
        this.mutations={};
        forEach(mutations,(key,fn)=>{
            
             this.mutations[key]=(params)=>{
                  fn.call(this,this.state,params);
             }
        })
        //配置 action

        this.actions={};
        let actions=options.actions ||{};
        
        forEach(actions,(key,fn)=>{
            this.actions[key]=(params)=>{
                fn.call(this,this.state,params);
           }
           

        })
        //對 modules 進行收集

        var modules=new ModuleCollection(options);
        console.log(modules);





    }
    get state(){
       return  this._vm

    }

    commit=(name,params)=>{
        this.mutations[name](params)

    }
    dispatch=(type,params)=>{
        this.actions[type](params);

    }

}



//安裝的方法
const install=(_Vue)=>{
   Vue=_Vue;
  //爲每一個組件注入
  Vue.mixin({
       
        beforeCreate(){
            //說明是根
            if(this.$options && this.$options.store)
            {
                this.$store=this.$options.store;

            }
            else{
                this.$store=this.$parent && this.$parent.$store;
            }


        }
  })

}
//必須處處install 方法
export default{
     install,
     Store
}
複製代碼

結語

至此咱們實現了一個簡易的Vuex,能夠基本模擬Vuex的經常使用場景,可是尚未實現modules的實現,加入了module就變得複雜不少。以上代碼就會有很大變更,可是核心原理沒有改變,咱們下一節繼續探究modules的實現。本人小白,若有錯誤,請諒解,並歡迎指正事件

下一節:juejin.im/post/5efe7c…

相關文章
相關標籤/搜索