vue源碼學習——數據驅動

vue的核心思想?

數據驅動

什麼是數據驅動?

數據驅動指的是視圖是由數據驅動生成,我們對視圖的修改不會直接操作DOM,而是修改數據。

模版和數據怎麼渲染成DOM的呢?

1. new Vue發生了什麼

Vue實際是一個類,只能通過new關鍵字初始化(在JavaScript中類是通過function實現的)
在這裏插入圖片描述
可以看到,new Vue會調用_init()方法,並且將參數options傳給這個方法。
在這裏插入圖片描述
合併參數,把參數options賦值給vue實例的$options
在這裏插入圖片描述
在初始化的最後,檢測到如果有el屬性,則調用vm.$mount方法掛載vm(vue實例),掛載的目的就是把模版渲染成DOM。

2. new Vue主要執行一些初始化的操作,Vue初始化主要乾了幾件事?

合併參數、初始化生命週期、初始化事件、初始化渲染、初始化data、props、computed、watcher等
在這裏插入圖片描述

3. 爲什麼在data中定義數據message可以直接通過this.message訪問到?

在初始化中有initState(vm)初始化狀態,找到initState方法
在這裏插入圖片描述
initState方法主要是實現props,methods,data,watch,computed的初始化
如果data存在,會初始化data,看看初始化data的方法initData(vm)
在這裏插入圖片描述

初始化data做了哪些事?

  1. 先從vue實例vm的$options中取到data

let data = vm.$options.data

  1. 將data賦值給vm._data,
    判斷data是不是一個function,如果是函數就調用getData方法,將data()返回的值賦值給data變量,如果不是function就不處理data

  2. 判斷最終的data是不是一個對象,如果不是對象就作出警告——data必須是一個對象

  3. 獲取data中的key,和props進行對比(就是說如果我在props中定義了一個id,就不能在data中定義id),不能重複的原因是因爲不管是data還是props他們的屬性最終都會掛載到vue實例上,通過this.id可以訪問到

  4. 最終會執行

在這裏插入圖片描述
在這裏插入圖片描述
![
首先理解Object.defineProperty()用法
Object.defineProperty()的作用就是直接在一個對象上定義一個新屬性,或者修改一個已經存在的屬性
Object.defineProperty(obj, prop, desc)
這個方法接受3個參數:

  1. obj需要定義屬性的當前對象(在這裏就是傳入的vue實例對象vm)
  2. prop需要定義或修改的屬性名,(這裏就是傳入的props或者data的key)
  3. desc 屬性描述符 是一個對象更(這裏指的是sharePropertyDefinition對象)

在這裏定義了描述對象的屬性描述符:
enumerable: true(可枚舉,就是是否出現在for…in或Object.keys中) configurable:true(是否配置,能否刪除)
在這裏插入圖片描述
sourceKey是傳入的參數_data或者_prop字符串
在這裏插入圖片描述
在這裏插入圖片描述
上面的target是傳入的vue實例對象,通過set和get的方法寫入或讀取數據,
從上面可以看出訪問data上的id通過this.id實際上是訪問了this._data.idthis._props.id

4. Vue實例掛載的實現

以下是Runtime+compiler版本的$mount方法實現

$mount方法
這個方法在platform目錄下的多個目錄下文件中都有定義,因爲這個方法的實現是和平臺和構建方式都相關的。
在這裏插入圖片描述
在這裏插入圖片描述

  1. 首先緩存了Vue原型上的$mount方法,然後再重新定義該方法
    爲什麼是重新定義呢?
    在這裏插入圖片描述

因爲在runtime/index.js中已經定義了$mount的方法,需要重新定義是因爲Runtime Only版本沒有$mount方法中的邏輯

  1. Runtime Only版本的$mount方法
    在這裏插入圖片描述
    這裏的query方法就是一個原生JavaScript API獲取DOM的方法
  2. Runtime Compiler版本的$mount方法
    在這裏插入圖片描述
    首先將el轉換爲DOM對象,然後對el做了限制,Vue不能掛載在body、html這樣的根節點上
    在這裏插入圖片描述
    然後判斷開發人員有沒有定義render方法,判斷有沒有寫template
    在這裏插入圖片描述
    如果template存在,再判斷template的類型,重新賦值template,判斷最後的template,編譯生成render函數
    說到底就是看有沒有render函數,因爲vue最終只認render函數,如果有render函數就直接調用render函數,如果沒有就將模版編譯生成render函數
    最後
    在這裏插入圖片描述
    最後調用調用緩存的mount方法(即走到了runtime/index.js裏面)
    在這裏插入圖片描述

最後執行mountComponent方法,這個方法做的事:如果沒有寫render函數,首先會將vm.$options.render賦值成一個空Node對象

vm.$options.render=createEmptyNode, 然後會嘗試錯誤提示,就是如果你使用的是Runtime Only版本卻沒有寫render函數卻寫了template警告,或者即沒有寫render函數又沒有寫template警告。

5. render方法做了哪些事情

Vue的_render方法是實例的一個私有方法,用來把實例渲染成一個虛擬Node(_render方法定義在src/core/instance/render.js中)

我們平時在開發過程中手寫render函數的場景比較少,寫得比較多的是template模版,template模版會被編譯成render方法。

render函數的第一個參數是createElement(createElement是一個函數vm.$createElement
vm.$createElement
在這裏插入圖片描述

createElement方法是在src/core/vdom/create-element下定義的
在執行initRender方法時候會調用createElement方法
可以看到除了又一個vm.$createElement方法外還定義了vm._c方法,那這兩個方法有什麼區別,他們內部都調用了createElement方法,只是最後一個參數傳得不同:

  1. vm._c方法是模版被編譯成render方法時調用的
  2. vm.$createElement方法是用戶手寫render函數時候調用的

總的來說:render方法最終是通過執行createElement方法並返回虛擬VNode(虛擬Node)

6. Virtual DOM(虛擬DOM)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章