Virtual-DOM的理解
在說Virtual-DOM之前,我們來先說下什麼是DOM,DOM從字面上來理解是文件物件模型。
W3C對DOM的定義是:“一個與系統平臺和程式語言無關的介面,程式和指令碼可以通過這個介面動態地訪問和修改文件內容、結構和樣式。”
而從上面的定義總結來看,DOM是介面,這個介面可以操作文件。
而文件呢就是Document,在HTML中的Document,可以簡單理解成一個節點樹,而我們要將這個節點樹對映成物件,而物件中自然就存在屬性和方法了,其中這些方法就讓我們可以操作文件(好像說的還是有點繞)
什麼是Virtual-DOM?
Virtual-DOM翻譯過來就是虛擬DOM,而它其實可以簡單理解為,通過JS去建立的表示DOM的物件,並且未載入到真實頁面中
- virtual-dom = js物件
- 未渲染到頁面中
有人說用virtual-dom比真實dom快,其實這是相對的,virtual-dom很多時候都不是最優的操作,但它具有普適性,在效率、可維護性之間達平衡
在網上看到一段程式碼,比較簡潔的描述瞭如何去建立一個virtual-dom:
//建立一個VNode的物件 class VNode { constructor(tag, children, text) { this.tag = tag this.text = text this.children = children } render() { if (this.tag === '#text') { return document.createTextNode(this.text) } let el = document.createElement(this.tag) this.children.forEach(vChild => { el.appendChild(vChild.render()) }) return el } } function v(tag, children, text) { if (typeof children === 'string') { text = children children = [] } return new VNode(tag, children, text) } /* let nodesData = { tag: 'div', children: [ { tag: 'p', children: [ { tag: 'span', children: [ { tag: '#text', text: 'baidu' } ] } ] }, { tag: 'span', children: [ { tag: '#text', text: 'alibaba' } ] } ] } */ let vNodes = v('div', [ v('p', [ v('span', [v('#text', 'baidu')]) ] ), v('span', [ v('#text', 'alibaba') ]) ]); console.log(vNodes.render())//建立真實DOM // 對比DOM樹變更 function patchElement(parent, newVNode, oldVNode, index = 0) { if (!oldVNode) { parent.appendChild(newVNode.render()) } else if (!newVNode) { parent.removeChild(parent.childNodes[index]) } else if (newVNode.tag !== oldVNode.tag || newVNode.text !== oldVNode.text) { parent.replaceChild(newVNode.render(), parent.childNodes[index]) } else { for (let i = 0; i < newVNode.children.length || i < oldVNode.children.length; i++) { patchElement(parent.childNodes[index], newVNode.children[i], oldVNode.children[i], i) } } } let vNodes1 = v('div', [ v('p', [ v('span', [v('#text', 'baidu')]) ] ), v('span', [ v('#text', 'ali') ]) ] )//虛擬DOM1 let vNodes2 = v('div', [ v('p', [ v('span', [ v('#text', 'jd') ]) ] ), v('span', [ v('#text', 'baidu'), v('#text', 'map') ]) ] )//虛擬DOM2 const root = document.querySelector('#root') patchElement(root, vNodes1) //對比更新 複製程式碼
我們從上面的程式碼可以清晰的看到 vdom的簡單流程
vue2引入的vdom是基於snabbdom 進行的修改而來,對於snabbdom的原始碼解析,我們可以看這裡
react的diff演算法,在16版本之前,與vue2應該大同小異 而在react16之後的fiber,採用了不同的方式
上面只是簡單的介紹了下virtual-dom的概念而已,而對於具體到底是如何進行vdom之間的diff,才是更核心的東西,我們後續再去研究它
更多內容請看blog