閱讀 剖析 Vue.js 內部運行機制,自己做點小筆記,方便自己可以隨時翻看,大家喜歡這篇文章,也可以去點擊看原作哦~
初始化及掛載
看圖可知,new Vue() 后,會調用 _init 函數來初始化,這個過程,包括生命周期、data、props、methods、事件、computed、watch等。其中,Object.defineProperty 設置 setter 、getter 函數,用來實現「響應式」以及「依賴收集」。
初始化后調用 $mount 掛載組件,如果是運行時編譯,即不存在 render function但是存在 template 的情況,需要進行「編譯」步驟。
編譯
compile 編譯可以分成 parse、optimize 與 generate 三個階段,最終需要得到 render function
響應式
當 render function 被渲染的時候,因為會讀取所需對象的值,所以會觸發(fā) getter 函數進行「依賴收集」,「依賴收集」的目的是將觀察者 Watcher 對象存放到當前閉包中的訂閱者 Dep 的 subs 中。形成如下所示的這樣一個關系
在修改對象的值的時候,會觸發(fā)對應的 setter, setter 通知之前「依賴收集」得到的 Dep 中的每一個 Watcher,告訴它們自己的值改變了,需要重新渲染視圖。這時候這些 Watcher 就會開始調用 update 來更新視圖
Virtual DOM
render function 會被轉化成 VNode 節(jié)點。Virtual DOM 其實就是一棵以 JavaScript 對象(VNode節(jié)點)作為基礎的樹,用對象屬性來描述節(jié)點,實際上它是一層對真實 DOM的抽象。最終可以通過一系列操作使這棵樹映射到真實環(huán)境上。由于 Virtual DOM 是以 JavaScript 對象為基礎而不依賴真實平臺環(huán)境,所以使它具有了跨平臺的能力,比如說瀏覽器平臺、Weex、Node 等。
比如說:
{
tag: 'div', /*說明這是一個div標簽*/
children: [ /*存放該標簽的子節(jié)點*/
{
tag: 'button', /*說明這是一個a標簽*/
text: 'click me' /*標簽的內容*/
}
]
}
渲染后:
<div>
<button>click me</button>
</div>
這只是一個簡單的例子,實際上的節(jié)點有更多的屬性來標志節(jié)點,比如 isStatic (代表是否為靜態(tài)節(jié)點)、 isComment (代表是否為注釋節(jié)點)等
更新視圖
前面說到,修改一個對象值的時候,通過 setter -> Watcher -> update 的過程來修改對應的視圖,那么,最終如何更新到視圖呢?
當數據變化時,執(zhí)行 render function 可以得到一個新的 VNode 節(jié)點,如果想得到新的視圖,簡單的方法就是直接解析 VNode 節(jié)點,用 innerHTML 全部渲染到真實的 DOM 中。但是,如果只對其中一小部分進行修改,哪咋辦?
那么,這時候就需要用的 「patch」了。會將新的 VNode 與舊的 VNode 一起傳入 patch 進行比較,然后 diff 算法得到差異。最后將差異的地方進行渲染即可
講到這里,我們在一起看看全部的流程圖