理解 Virtual DOM
內部工作機制
本章節,大喵將帶着大家,深入瞭解下我們常用的MVVM框架的核心虛擬DOM的工作原理;相信大家對虛擬DOM的認識,並不陌生,目前萊索很多跨平臺前端產品的誕生都是由於虛擬DOM的盛行,纔會產生這麼多跨平臺開發框架;所以熟悉和了解Virtual DOM
對一名前端開發工程師來說,是非常有必要的。所以跟着大喵一起來學習研究吧 ~
參考資料:
- https://segmentfault.com/a/1190000010157277
- https://segmentfault.com/a/1190000016647776
簡單搜索列表結構
這是一個簡單地可篩選的搜索應用,它包含了兩個組件FilteredList
和List
。List
組件用來渲染一組items
(默認:“California"和"New York”)。這個應用有一個搜索框,可以根據字母來過濾列表項。展示非常地直觀:
從上面的結構圖片我們可以觀察到3
部分的結構,“真實DOM”、“DOM tree 樹”、“VDOM 虛擬DOm對象”,非常直觀,從上面的結構,我們可以得出結論,虛擬DOM就是一個js
對象,一個用來描述DOM樹的javascript
對象,我們需要更新這個對象,然後去更新我們頁面中的DOM結構。
JSX轉換成DOM的過程
我們使用jsx
來寫組件,它會被babel
轉換成純js
,然後Preact
的h
函數會將這段js
轉換成DOM
樹,最後Preact
的Virtual DOM
算法會最終轉換成真實的DOM
樹,來構建我們的應用。
Babel 和 JSX
在React,Preact這樣的類庫中,沒有HTML標籤,取而代之的是,一切都是javascript。所以,我們會像下面這樣來寫HTML:
這就是jsx的由來。jsx本質上就是允許我們在javascript中書寫HTML!並且允許我們在HTML中通過使用花括號來使用js。jsx幫助我們像下面這樣寫組件:
Jsx 轉換成 Js
jsx
很酷,但它不是合法的js
,並且最終我們需要的是真實的DOM。JSX
只是幫助編寫一個真實DOM的替代品,除此之外,它別無用處。所以我們需要一種方法將它轉換成對應的JSON對象(也就是Virtual DOM),作爲轉化成真實DOM的輸入。我們需要一個函數來實現這個功能。
在Preact
中h
函數就是幹這件事情的,等同於React
中的React.createElement
。
但是如何將jsx
轉換成h
函數的調用呢?Babel
就是幹這件事情的。Babel
遍歷每個jsx
節點,並將它們轉換成h函數調用。
Babel JSX(React vs Preact)
默認情況下,Babel將jsx轉換成React.createElement調用
但是我們可以很容易地將函數名修改成任何名稱,只需要在·babelrc
中配置一下即可
Option 1:
//.babelrc
{ "plugins": [
["transform-react-jsx", { "pragma": "h" }]
]
}
Option 2:
//Add the below comment as the 1st line in every JSX file
/** @jsx h */
掛載到真實DOM
不僅僅是render中的代碼會被轉換成h函數,最初的掛載也會!這就是代碼執行開始的地方:
//Mount to real DOM
render(<FilteredList/>, document.getElementById(‘app’));
//Converted to "h":
render(h(FilteredList), document.getElementById(‘app’));
h
函數的輸出
h
函數將jsx
轉化後的內容轉換成Virtual DOM
節點。一個Preact的Virtual DOM節點就是一個簡單的代表了單個包含屬性和子節點的DOM節點的js對象,如下所示:
{
"nodeName": "",
"attributes": {},
"children": []
}
比如,應用的input標籤對應的Virtual DOM如下:
{
"nodeName": "input",
"attributes": {
"type": "text",
"placeholder": "Search",
"onChange": ""
},
"children": []
}
注意:h
函數並不是創建整棵樹!
Preact中的Virtual DOM算法
在下面的流程圖中,展示了在Preact
中,組件是如何被創建、更新和刪除的過程。同時也展示了像componentWillMount
這樣的生命週期事件是什麼時候被調用的。