一、前言
虛擬DOM概念隨着react的誕生而誕生,由facebook提出,其卓越的性能很快得到廣大開發者的認可;繼react之后vue2.0也在其核心引入了虛擬DOM的概念,本文將以vue2.0使用的snabbdom入手,來介紹虛擬DOM的主要實現原理。
二、虛擬DOM
在開始介紹snabbdom之前我們想來想兩個問題,
(1)什么是虛擬DOM?
vdom可以看作是一個使用javascript模擬了DOM結構的樹形結構,這個樹結構包含整個DOM結構的信息,如下圖:

(2)為什么要使用虛擬DOM?
虛擬DOM就是為了解決瀏覽器性能問題而被設計出來的
三、snabbdom
要了解snabbdom的話有必要先去github上先了解下snabbdom: https://github.com/snabbdom/snabbdom
在這里看到官方給的一個example

這里可以看到列出來的兩個主要的核心函數,即h()函數和patch()函數,我們先來看下h()函數:
h函數

可以看到創建的虛擬DOM樹里面的結構在左邊的vnode里都有體現,所以現在看來我們的虛擬DOM結構樹和snabbdom中的h()函數是完全可以對應起來的,可以通過一個方法將虛擬DOM結構轉化成vnode;而上圖中newVnode則指的是虛擬DOM樹中的數據發生變化之后生成的vnode。
我們在回過頭來看patch()函數
patch函數
patch函數的執行分為兩個階段,兩次傳遞的參數都是兩個
第一階段為虛擬dom的第一次渲染,傳遞的兩個參數分別是放真實DOM的container和生成的vnode,此時patch函數的作用是用來將初次生成的真實DOM結構掛載到指定的container上面。
第二階段傳遞的兩個參數分別為vnode和newVnode,此時patch函數的作用是使用diff算法對比兩個參數的差異,進而更新參數變化的DOM節點;
可以發發現h函數和patch函數在cnabbdom中實現vdom到真實DOM的轉化起到了至關重要的作用,那么還有一個很重要的環節,patch函數中是怎么樣實現對比兩個vnode從而實現對真實DOM的更新的呢,這里還要提一下snabbdom的另外一個核心算法,即diff算法。
diff算法
其實在我們日常開發中我們都在接觸類似與diff算法的一些軟件,比如svn可以看到當前代碼和svn服務器上代碼的不同之處,再如Beyond Compare這款軟件也可以為我們指出兩個對比文件的不同之處
但是此處是如何實現對vnode的對比的呢?參考以下代碼:
1 function updateChildren(vnode, newVnode) { // 創建對比函數
2 var children = vnode.children || []
3 var newChildren = newVnode.children || []
4
5 children.forEach(function(childrenVnode, index) {
6 var newChildVnode = newChildren[index] // 首先拿到對應新的節點
7 if (childrenVnode.tag === newChildVnode.tag) { // 判斷節點是否相同
8 updateChilren(childrenVnode, newChildVnode) // 如果相同執行遞歸,深度對比節點
9 } else {
10 repleaseNode(childrenVnode, newChildVnode) // 如果不同則將舊的節點替換成新的節點
11 }
12 })
13 }
14
15
16 function repleaseNode(vnode, newVnode) { // 節點替換函數
17 var elem = vnode.elem
18 var newEle = createElement(newVnode)
19 }
此處簡單的列舉了一下diff算法的原理,以上是最簡單的對比,更復雜的對比函數包括對節點的增刪以及其它的節點邏輯就不一一贅述了,這里最重要的一部分就是遞歸的使用,才能將vnode進行深度對比。

