1. 程式人生 > 程式設計 >Javascript 虛擬 DOM詳解

Javascript 虛擬 DOM詳解

目錄
  • 什麼是虛擬 dom?
  • 為什麼需要虛擬dom?
  • 虛擬dom是如何轉換為真實dom的?
  • 模板和虛擬dom的關係
  • 注入
  • 掛載
  • 完整流程
  • 總結

什麼是虛擬 dom?

虛擬 dom 本質上就是一個普通的物件(mounted 中列印 this. _vnode 就是該物件內容),用於描述檢視的介面結構

在中,每個元件都有一個render函式,每個render函式都會返回一個虛擬dom樹,這也就意味著每個元件都對應一棵虛擬DOM樹

在這裡插入圖片描述

vnode 是一個普通的 JS 物件,用於描述介面上應該有什麼,比如:

var vnode = {
  tag: "h1",children: [
    { tag: undefined,text: "第一個vue應用:Hello World"}
  ]
}

上面的物件描述了:

有一個標籤名為 h1 的節點,它有一個子節點,該子節點是一個文字,內容為「第一個vue應用:Hello World」

為什麼需要虛擬dom?

在vue中,渲染檢視會呼叫render函式,這種渲染不僅發生在元件建立時,同時發生在檢視依賴的資料更新時。如果在渲染時,直接使用真實DOM,由於真實DOM的建立、更新、插入等操作會帶來大量的效能損耗,從而就會極大的降低渲染效率。

因此,vue在渲染時,使用虛擬dom來替代真實dom,主要為解決渲染效率的問題。

對比建立js物件和真實 dom 物件效率:

在這裡插入圖片描述

結果:

在這裡插入圖片描述

建立一個真實的 dom 會伴隨著建立許多的屬性

在這裡插入圖片描述

虛擬dom是如何轉換為真實dom的?

在一個元件例項首次被渲染時,它先生成虛擬dom樹,然後根據虛擬dom樹建立真實dom,並把真實dom掛載到頁面中合適的位置,此時,每個虛擬dom便會對應一個真實的dom。如果頁面只會重新整理一次,後續不會有資料更新等問題的情況下,用虛擬 dom 的方式是比直接顯示真實 dom 效率低的。

如果一個元件受響應式資料變化的影響,需要重新渲染時,它仍然會重新呼叫render函式,創建出一個新的虛擬dom樹,用新樹和舊樹對比,通過對比,找出差異,然後僅更新差異部分的虛擬dom節點,最後,這些更新過的虛擬節點,會去修改它們對應的真實dom

這樣一來,就保證了對真實dom達到最小的改動。

在這裡插入圖片描述

模板和虛擬dom的關係

vue框架中有一個compile(編譯)模組,它主要負責將模板轉換為render函式,而render函式呼叫後將得到虛擬dom。

編譯的過程分兩步:

1.將模板字串轉換成為AST(抽象語法樹:用js樹形結構來描述我們原始的程式碼;線上工具:https://astexplorer.net/)

2.將AST轉換為render函式

vue 模板並不是真實的 DOM,它會被編譯為虛擬 DOM

<div id="app">
  <h1>第一個vue應用:{{title}}</h1>
  <p>作者:{{author}}</p>
</div>

上面的模板會被編譯為類似下面結構的虛擬 DOM

{
  tag: "div",children: [
    { tag: "h1",children: [ { text: "第一個vue應用:Hello World" } ] },{ tag: "p",children: [ { text: "作者:袁" } ] }
  ]
}

如果使用傳統的引入方式(script src="...vue.js"),則編譯時間發生在元件第一次載入時,這稱之為執行時編譯。

如果是在vue-cli的預設配置下,編譯發生在打包時(npm run build),打包之後就沒有模板只有 render 函數了,這稱之為模板預編譯。

編譯是一個極其耗費效能的操作,預編譯可以有效的提高執行時的效能,而且,由於執行的時候已不需要編譯,vue-cli在打包時會排除掉vue中的compile模組,以減少打包體積

打包時是否需要包含compile模組,是通過vue.config.js中的runtimeCompiler: true來控制的,預設 false,不包含。不建議更改該配置

模板的存在,僅僅是為了讓開發人員更加方便的書寫介面程式碼

vue最終執行的時候,最終需要的是render函式,而不是模板,因此,模板中的各種語法,在虛擬dom中都是不存在的,它們都會變成虛擬dom的配置

在vue-cli中如果同時存在template和render,由於存在一個打包過程,其中的模板預編譯會生成render覆蓋原有的render函式

在 vue 中如果同時存在template和renderwww.cppcns.com,一定是以render為準

虛擬 DOM 樹會最終生成為真實的 DOM 樹

在這裡插入圖片描述

vue通過以下邏輯生成vnode tree:

在這裡插入圖片描述

注意http://www.cppcns.com:虛擬節點樹必須是單根的

注入

在這裡插入圖片描述

vue會將以下配置注入到vue例項:

  • data:和介面相關的資料
  • computed:通過已有資料計算得來的資料,將來詳細講解
  • methods:方法

模板中可以使用vue例項中的成員

為了防止名稱衝突。因為會將data中資料代理http://www.cppcns.com給vue,假如說我們自己寫的data名稱和vue中自帶的屬性衝突了,那麼就會覆蓋vue內部的屬性,所以vue會把自己內部的屬性成員名稱前加上 或 , 如 果 加 上 的 是 或_,如果加上的是 或,http://www.cppcns.com​如果加上的是,代表是我們可以使用的,如果加上的是_,是vue自己內部使用的方法或屬性,我們不需要呼叫

掛載

將生成的真實 DOM 樹,放置到某個元素位置,稱之為掛載

掛載的方式:

1.通過el:"選擇器"進行配置

2.通過vue例項.$mount(“css選擇器”)進行配置

完整流程

  • 例項被建立: new Vue()
  • 注入完成之後才會有響應式,能監聽到資料變化
  • 編譯生成虛擬 DOM 樹:首先找 render 函式,沒有就找模板把它生成 render,最後執行 render,生成虛擬 DOM 樹
  • 掛載完成:頁面上顯示

在這裡插入圖片描述

總結

本篇文章就到這裡了,希望能夠給你帶來幫助,也希望您能夠多多關注我們的更多內容!