【Vue原理】Props - 源碼版

寫文章不容易,點個讚唄兄弟
專一 Vue 源碼分享,文章分爲白話版和 源碼版,白話版助於理解工做原理,源碼版助於瞭解內部詳情,讓咱們一塊兒學習吧
研究基於 Vue版本 【2.5.17】

若是你以爲排版難看,請點擊 下面連接 或者 拉到 下面關注公衆號也能夠吧函數

【Vue原理】Props - 源碼版 學習

今天記錄 Props 源碼流程,哎,這東西,就算是研究過了,也真是會隨着時間慢慢忘記的。this

幸虧我作了詳細的文章,忘記了什麼的,回憶起來必然是很快的。spa

好的,回到正題,Props代理

請你在讀這篇以前,先去看看個人白話版code

【Vue原理】Props - 白話版 對象

在上面這篇文章中,也已經清楚地解決了一個問題遞歸

父組件 如何 把數據 當作 props 傳給子組件token

因此今天,咱們只需記錄 Props 的處理流程源碼便可開發


初始化

在建立Vue實例的過程當中,會調用 initState 處理options,好比 props,computed,watch 等

只要你 new Vue 建立實例以後,很快就會處理options

function Vue(){
    ... 其餘處理
    initState(this)

    ...解析模板,生成DOM 插入頁面

}

function initState(vm) {    

    var opts = vm.$options;    

    if (opts.props) {

        initProps(vm, opts.props);
    }

    ... 處理 computed,watch,methods 等其餘options

}

initProps

你看處處理 Props ,主要用到了一個方法 initProps,他就是本場的焦點了,讓咱們來採訪下源碼本碼

function initProps(vm, propsOpt) {    
   // 這是父組件給子組件傳入的 props 的具體值

   var propsData = vm.$options.propsData || {};    

   var props = vm._props = {};    

   for (var key in propsOpt){        

       // 給 props 的 key 設置 響應式

       defineReactive(props, key,  propsData[key]);        

       if (! (key in vm)) {            

           // 轉接訪問,訪問 vm 屬性,轉到訪問 vm._props 屬性
           proxy(vm, "_props", key);
       }
   }
}

上面的代碼主要作了三件事

一、遍歷 props

二、給 props 設置響應式

三、給 props 設置代理

咱們主要講兩件事

一、給 props 設置響應式

defineReactive(props, key,  propsData[key])

defineReactive 在這裏就不給太多源碼了,你只須要記住他就是給 props 設置響應式的

function defineReactive(obj, key) {    

    Object.defineProperty(obj, key, {  

        get() { ...依賴收集 },
        set(newVal) { ....依賴更新 }
    });
}

若是你想了解響應式,就能夠看我這篇文章

【Vue原理】響應式原理 - 白話版

Props 設置響應式,也是旨在數據改變時動態更新。

怎麼設置響應式嗎?看這裏

【Vue原理】依賴收集 - 源碼版之基本數據類型

【Vue原理】依賴收集 - 源碼版之引用數據類型

數據是直接從 父組件上傳過來的,沒有進行拷貝等處理,原樣傳過來

怎麼傳的?也能夠看

【Vue原理】Props - 白話版

若是props 是基本類型

在 子組件實例上設置這個 props 屬性爲響應式,跟 data 本質同樣,做用是監聽 props 修改

若是 props 是對象

也會在 子組件實例上 設置這個 props 屬性爲響應式,做用也是監聽 props 修改

可是!

【不會遞歸對象】給對象內全部屬性設置響應式,由於該對象【已經在父組件中】完成響應式設置了

也就是說

若是你在 子組件中直接修改 props 對象內的數據,父組件也會跟着修改

在記錄的途中,我發現了一個問題,發現沒有想象中的那麼簡單,因此如今鄭重記錄

當 父組件數據 改變,子組件怎麼更新?

分類型的,說得比較詳細,可能有點繞?

一、 若是是基本類型,是這個流程

父組件數據改變,只會把新的數據傳給子組件

子組件拿到新數據,就會直接替換到原來的 props

替換就是直接等哈,看下源碼,重要語句標紅

updateChildComponent 是子組件內部更新時會調用到的一個函數,這是其中更新 props 的一個片斷

function updateChildComponent(

    vm, propsData

) {    

    if (propsData && vm.$options.props) {        

      // 保存 props 的地方,用於訪問轉接,具體看文章下面

      var props = vm._props;        

      // 全部子組件上設置的 props 的 key

      var propKeys = vm.$options._propKeys || [];        

      for (var i = 0; i < propKeys.length; i++) {            

        var key = propKeys[i];

        props[key] = propsData[key]
      }
     vm.$options.propsData = propsData;
   }
}

而 props 在子組件中也是響應式的,【直接 等號 替換】致使觸發 set,set 再通知 子組件完成更新

公衆號

公衆號

數據是 基本類型,而後設置定時器修改數據

watcher1 是父組件,watcher2 是子組件

父組件內的 data num 通知 watcher1 更新
子組件內的 props child_num 通知 watcher2 更新

公衆號

二、若是是對象,是這個流程

條件

父組件傳 對象 給 子組件,而且父子組件 頁面都使用到了這個數據

結果

那麼這個對象,會收集到 父子組件的 watcher

因此

當 對象內部被修改的時候,會通知到 父和子 更新。

例子

父組件設置 obj 對象,並傳給子組件

公衆號

公衆號
定時修改父組件數據 obj.name ,能夠看到是 obj.name 通知 父子更新

公衆號

固然,若是對象被整個替換了,而不是修改內部,那麼跟 基本類型同樣

區別是什麼?

一、基本類型是,子組件內部 props 通知 子組件更新的

二、引用類型是,父組件的數據 data 通知 子組件更新的

二、給 props 設置代理

在白話版中,我已經說得很清楚了, Props 有個移花接木的暗箱操做,就是訪問轉移

Data 也是這麼作的

[
【Vue原理】代理 Data - 源碼版 ]( https://mp.weixin.qq.com/s?__... )

你在項目中,會使用 http://this.xxx去訪問 props,props 已經當成了 實例的屬性,因此能夠直接訪問

可是其實你訪問的是 【this._props.xxx】

爲何 Vue 要這麼弄,目的就是爲了方便開發啊,讓咱們直接簡短了相關代碼

而 React,訪問 props,還要 this.props.xxxx,寫這麼長,不嫌麻煩嗎?

那麼,是怎麼設置代理的呢,就是下面這行

proxy(vm, "_props", key);

proxy 是什麼也不要急,瓜就在下面,拿凳坐好

function proxy(

    target, sourceKey, key

) {    

  Object.defineProperty(target, key, {

      get() {            

          return this[sourceKey][key]

      },

      set(val) {            

          this[sourceKey][key] = val;

      }
  });
}

這段代碼作了2 個事

一、使用 props 在 vm 上佔位,使得能夠經過 http://vm.xxx 的形式訪問到 props

二、設置 [Object.defineProperty] 的 get 和 set ,間接獲取和賦值 vm._props

全部訪問賦值 props,轉接到 vm._props 上,直觀以下圖

公衆號
上個實例,方便你們看

公衆號

說完收工

公衆號

相關文章
相關標籤/搜索