虛擬 DOM 和 DOM diff

概念

  • 虛擬DOM

  • 是什么:其實就是個js對象
    虛擬 dom 是相對于瀏覽器所渲染出來的真實 dom 的,在react,vue等技術出現之前,我們要改變頁面展示的內容只能通過遍歷查詢 dom 樹的方式找到需要修改的 dom 然后修改樣式行為或者結構,來達到更新 ui 的目的。
    這種方式相當消耗計算資源,因為每次查詢 dom 幾乎都需要遍歷整顆 dom 樹,如果建立一個與 dom 樹對應的虛擬 dom 對象( js 對象),以對象嵌套的方式來表示 dom 樹,那么每次 dom 的更改就變成了 js 對象的屬性的更改,這樣一來就能查找 js 對象的屬性變化要比查詢 dom 樹的性能開銷小。

  • 優點:1. 減少不必要的DOM操作 2. 能跨平臺渲染

  • 缺點:

需要額外的創建函數,如 React 中的 createElement 或者 Vue 中的 h可以通過 JSX 來簡化成 XML 寫法 ,但 是需要額外的構建過程,嚴重依賴打包工具

  • DOM diff

  • 是什么:一個函數:虛擬DOM的對方算法的一個函數patches=patch(oldVNode,newVNode)

  • 優點:減少DOM操的次數(只需要操作變化的節點)

  • 缺點:同級節點對比存在bug(key)

關于DOM的謠言:DOM操作慢,虛擬操作DOM快?

  • 慢是相比于原生js的api,
  • 但是任何基于DOM庫的(Vue/React)都不可能在操作DOM時比DOM快

為什么有謠言呢?

  • 因為確實有時 虛擬DOM快:比如下面的例子

虛擬DOM長什么樣子

  1. 在React中的虛擬DOM
const vNode = {
  key: null,
  props: {
    children: [
      {type: 'span', ...},
      {type: 'span', ...}
    ],
    className: "red",
    onClick: ()=>{}
  },
  ref: null,
  type: "div",
  ...
}
  1. 在Vue中的虛擬DOM
const vNode = {
  tag: 'div',
  data: {
    class: 'red',
    on: {
      click: ()=>{}
    }
  },
  children: [
    {tag: "span", ...},
    {tag: "span", ...}
  ],

創建虛擬DOM

  1. React
  createElement('div',{className:'red',onClick:()=> {}},[
    createElement('span', {}, 'span1'),
    createElement('span', {}, 'span2')
  ]
)
// 通過 JSX 簡化
<div className="X" onClick="{()=> {}}">
    <span>span1</span>
    <span>span2</span>
</div>
//  通過 babel 轉為 createElement 形式
  1. Vue
//  只能在 render 函數里得到 h
h('div', {
  class: 'red',
  on: {
    click: () => { }
  },
}, [h('span',{},'span1'), h('span', {}, 'span2'])
   
   
 // 通過簡化JSX
<div class="red" @click="fn">
  <span>span1</span>
  <span>span2</span>
</div>
// 通過 vue-loader 轉為 h 形式

DOM diff

  1. 把虛擬DOM想象成樹形
    舉例一:
<div :class="x">
    <span v-if="y">{string1}</span>
    <span>{string2}</span>
</div>
image

當數據變化,x從red變為green

image

此時DOM diff發現:

  • div標簽類型沒變,只需要更新div對應的DOM的屬性。
  • 子元素沒變不更新
    舉例二:
    當數據變化,y從true變為false
    image

    DOM diff發現:
  • div沒變,不用更新。
  • 子元素1標簽沒變,但是children變了,更新DOM 內容
  • 子元素2不見了,刪除對應的DOM
    DOM diff總結:
  • 虛擬 DOM 的對比算法
  • 一個被稱為 patch 的函數
  • patches = patch(oldVNode, newVNode)
  • patches 就是要運行的 DOM 操作
    即給兩個虛擬節點,返回對應的 DOM 操作
    DOM diff優點:
  1. 能減少不必要的DOM操作
    2.能跨平臺渲染
    DOM diff缺點:
  2. 需要額外的創建函數,如createElement或h,但是可以通過JXS來簡化成XML寫法。
  3. 同級節點對比存在bug??解決方法:用Key值進行區分

舉個栗子

如不加key的三個同級input標簽,分別輸入不同value:1、2、3,然后點擊刪除第二個,會發現留下的兩個input中,value值是1、2而不是1、3。

image

點擊刪除2,你以為2被刪除了,結果卻是:

image

因為中間的刪除第三個取代第二個的位置這個是我們人類認為的邏輯,計算機認為的邏輯是:第二個的改變,第三個的刪除(神奇的算法邏輯)。

如何解決?

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容