VUE源碼解析


flow類型檢查

Vue.js 的源碼使用了Flow做靜態類型檢查,之所以選擇Flow , 是因為 Babel和 ESlint 都有對應的Flow插件支持語法。

 

目錄源碼解析 

compiler  目錄包含Vue.js 所有編譯相關的代碼。它包括把模板解析成AST語法樹,AST語法樹優化,代碼生成等功能

core        目錄包含了Vue.js的核心代碼,包括內置組件、全局API封裝、Vue實例化、觀察者、虛擬DOM、工具函數等

platfrom   Vue.js是一個跨平台的MVVM框架,可以跑在web 或者配合weex 跑在natvie客戶端上。這里兩個目錄對應兩個平台的打包入口

server      目錄包含了服務端渲染的邏輯,這部分代碼是跑在服務器的node.js

sfc          目錄包含了把 .vue 文件內容解析成一個 javascript 對象

shared     目錄包含了一些定義的工具方法,這些方法會被瀏覽器端的Vue.js 和服務端的Vue.js 共同使用

 

Vue的初始化過程

Vue的本質上就是一個用Function實現的Class類,然后它的原型prototypey以及它本身都擴展了一系列的方法和屬性。

在 import Vue 的時候,會執行core 文件夾中的 index.js ,  通過 instance文件夾中的index.js文件給Vue的prototype上擴展一些方法;通過 initGlobalAPI 方法擴展 nextTick 、set、del 等全局靜態方法。

new Vue的時候,會調用 this._init 方法, 通過該方法,合並配置、初始化生命周期、初始化事件中心、初始化渲染、初始化data 、props、computed、watcher 等等。初始化最后,檢測到如果有el 屬性,則調用 vm.$mount 方法掛載vm, 把模板渲染成最終的DOM 。

$mount 方法 先對 el 做了限制 , Vue 不能掛載在 body 、html 這樣的根節點上。Vue組件的最后渲染都需要render方法,如果沒有定義render 方法,則會把 el 或者 template 字符串轉換成 render 方法,這個過程是Vue的一個在線編譯過程,它是通過 compileToFunctions 方法實現的。

$mount 方法支持傳入兩個參數,第一個是 el ,表示掛載的元素,可以是字符串,也可以是DOM對象,如果是字符串在瀏覽器環境下會調用 query 方法轉換成DOM對象;第二個參數是和服務端渲染相關。

$mount 方法實際上調用的是 mountComponent 方法,mountComponent 方法的核心是先調用 vm._render 方法生成虛擬DOM , 再實例化一個渲染 Watcher (觀察者) , 在它的回調函數中會調用 updateComponent 方法,最終調用vm._update更新DOM 。

Watcher 在這里的作用,一是初始化的時候會執行回調函數,二是當 vm實例中的監測的數據發生變化的時候執行回調函數。函數最后判斷為根節點的時候設置 vm._isMounted 為 true , 表示這個實例已經掛載了,同時執行 mounted 鈎子函數。 vm.$vnode 表示 Vue實例的父虛擬 Node , 為 null 時表示當前是 根Vue 的實例。

vm._render 方法最終是通過執行 createElement 方法並返回 vnode , 它是一個虛擬 node ,接下來通過 vm._update 方法渲染成一個真實的DOM並渲染出來

vm._update 被調用的時機有兩個,一是首次渲染,二是數據更新的時候。vm._update的核心是調用 vm._patch_ 方法,這個方法在web 和 weex 平台上的定義是不一樣的。 該方法內部 調用 insert 方法把DOM插入父節點中。

patch的整體流程:createComponent -> 子組件初始化  ->  子組件render  -> 子組件patch      嵌套組件的插入順序是先子后父

Vue各組件間合並配置過程:對於options的合並方式有2種,子組件初始化過程通過 initInternalComponent 方式要比外部初始化Vue通過 mergeOptions 的過程要快,合並完的結果保留在 vm.$options 中。 

源碼中最終執行生命周期的函數都是調用 callHook 方法

 

異步組件

Vue的異步組件有3種方式,高級異步組件實現了 loading 、resolve、reject、timeout 4種狀態,異步組件實現的本質是2次渲染,除了0 delay的高級異步組件第一次直接渲染成 loading組件外,其他都是第一次渲染生成一個注釋節點,當異步獲取組件成功后,再通過 forceRender 強制重新渲染。

 

依賴收集/派發更新

收集依賴的目的是為了當這些響應式數據發生變化,觸發它們的 setter 的時候,能知道應該通知哪些訂閱者去做相應的邏輯處理,我們把這個過程叫做派發更新。

當數據發生變化時,觸發 setter 邏輯,把在依賴過程中訂閱的所有觀察者,也就是 wather,都觸發它們的 update 過程,這個過程又利用隊列做了進一步優化,在 nextTick 后執行所有 watcher 的 run ,最后執行它們的回調函數。

 

計算屬性/偵聽屬性

計算屬性的本質是 computed watcher  

偵聽屬性的本質是 user watcher,它還支持deep、sync、immediate等配置

 

組件更新

組件更新的過程就是新舊 vnode diff , 對新舊節點相同以及不同的情況分別做不同的處理。

新舊節點不同的更新流程是  創建新節點 -> 更新父占位符節點 ->  刪除舊節點 ;

新舊節點相同的更新流程是去獲取它們的 childern , 根據不同情況做不同的更新邏輯。

新舊節點相同且它們都存在子節點,那么會執行 updateChildren 邏輯 。


免責聲明!

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



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