虛擬DOM的解讀

2021-10-04 19:45:18 字數 4487 閱讀 2729

我們知道virtual dom的作用是為了避免直接操作dom,因為直接操作dom是一件很費效能的事情,但是虛擬dom最後要渲染成真實的dom,也是需要採用dom操作的,那效能優化,優化在**?

var element = ,

children: [ // 該節點的子節點

, children: ["item 1"]},

, children: ["item 2"]},

, children: ["item 3"]},

]}

上面對應的html結構是:

既然dom節點可以用js物件來表示,那麼一整個dom樹,當然也可以用js物件來表示。

js物件模擬dom物件的乙個簡單的實現:

export default class element  tag 'div'

* @param props

* @param children [ element1, 'text']

* @param key option

*/constructor(tag, props, children, key) else if (isstring(children))

if (key) this.key = key

} // 渲染

render()

create()

// 建立節點

_createelement(tag, props, child, key)

}if (key)

// 遞迴新增子節點

if (child) else })}

return el

}}

我們在比對dom樹差異的時候,是會用到樹的遞迴的,在我們實現之前,先考慮好兩個節點之間的對比會有哪些情況

import  from './util'

import element from './element'

export default function diff(olddomtree, newdomtree)

// 一開始的索引為 0

dfs(olddomtree, newdomtree, 0, pathchs)

return pathchs

}function dfs(oldnode, newnode, index, patches) else if (newnode.tag === oldnode.tag && newnode.key === oldnode.key) )

// 遍歷子樹

diffchildren(oldnode.children, newnode.children, index, patches)

} else )

} if (curpatches.length) else

}}

判斷屬性更改也分為三個步驟

function diffprops(oldprops, newprops) )

}} for (const key in newprops) )

} else if (!oldprops[key]) )}}

} return change

}

這裡的步驟其實跟判斷屬性差異類似的,也是分為三步。

function listdiff(oldlist, newlist, index, patches) 

// 尋找新的 children 中是否含有當前節點

// 沒有的話需要刪除

let index = newkeys.indexof(key)

if (index === -1) else list.push(key)

})// 遍歷變更後的陣列

let length = list.length

// 因為刪除陣列元素是會更改索引的

// 所有從後往前刪可以保證索引不變

for (let i = length - 1; i >= 0; i--) )

}} // 遍歷新的 list,判斷是否有節點新增或移動

// 同時也對 `list` 做節點新增和移動節點的操作

newlist &&

newlist.foreach((item, i) =>

// 尋找舊的 children 中是否含有當前節點

let index = list.indexof(key)

// 沒找到代表新節點,需要插入

if (index === -1 || key == null) )

list.splice(i, 0, key)

} else )

move(list, index, i)}}

})return

}function getkeys(list) else if (item instanceof element)

keys.push(key)

})return keys

}

對於這個函式來說,主要功能就兩個

function diffchildren(oldchild, newchild, index, patches)  = listdiff(oldchild, newchild, index, patches)

if (changes.length) else

} // 記錄上乙個遍歷過的節點

let last = null

oldchild &&

oldchild.foreach((item, i) =>

} else index += 1

last = item

})}

通過之前的演算法,我們已經可以得出兩個樹的差異了。既然知道了差異,就需要區域性去更新 dom 了,下面就讓我們來看看 virtual dom 演算法的最後一步驟

這個函式的主要兩個功能

let index = 0

export default function patch(node, patchs)

let last = null

if (childnodes && childnodes.length) )

}}function changedom(node, changes, nochild) = change

switch (type) = change

props.foreach(item => else

})break

case stateenums.remove:

node.childnodes[change.index].remove()

break

case stateenums.insert:

let dom

if (isstring(change.node)) else if (change.node instanceof element)

node.insertbefore(dom, node.childnodes[change.index])

break

case stateenums.replace:

node.parentnode.replacechild(change.node.create(), node)

break

case stateenums.move:

let fromnode = node.childnodes[change.from]

let tonode = node.childnodes[change.to]

let clonefromnode = fromnode.clonenode(true)

let cloentonode = tonode.clonenode(true)

node.replacechild(clonefromnode, tonode)

node.replacechild(cloentonode, fromnode)

break

default:

break}})

}

virtual dom演算法的實現主要總結為三步

let test4 = new element('div', , ['test4'])

let test5 = new element('ul', , ['test5'])

let test1 = new element('div', , [test4])

let test2 = new element('div', , [test5, test4])

let root = test1.render()

let pathchs = diff(test1, test2)

console.log(pathchs)

settimeout(() => , 1000)

優缺點:

優點:

缺點:

虛擬dom 虛擬 DOM 和 DOM diff

乙個能代表dom樹的物件,通常含有標籤名 標籤上的屬性 事件監聽和子元素及其它屬性。虛擬dom在vue和react中的示例 const rnode classname red 標籤上的屬性 onclick 事件 ref null,type div 標籤名 or 元件名 const vnode 事件 ...

vue虛擬DOM是什麼?vue的虛擬DOM的用法

vue虛擬dom是什麼?vue的虛擬dom的用法 1 為什麼需要虛擬dom 雖然採用的是文件碎片,但是操作的還是真實的dom。而我們知道操作dom的代價是昂貴的,所以vue2.0採用了虛擬dom來代替對真實dom的操作,最後通過某種機制來完成對真實dom的更新,渲染檢視。所謂的虛擬dom,其實就是用...

虛擬DOM與真實DOM

先來個簡單的react例子 1.建立虛擬dom const vdom hello react h1 此處不要寫引號,因為不是字串 2.渲染虛擬dom到頁面 reactdom.render vdom document.getelementbyid test script head test div b...