摘要:什么是虛擬舉例說明如果網頁中有一個表格,表頭是姓名,年級,分數。即我們用虛擬的結構替換需要處理的結構,對虛擬的進行操作之后再進行渲染,就成為了真實的數據。當狀態變更的時候用修改后的新渲染的的對象和舊的虛擬對象作對比,記錄著兩棵樹的差異。
虛擬DOM
可以看看這個文章
如何理解虛擬DOM? - 戴嘉華的回答 - 知乎
https://www.zhihu.com/questio...
深度剖析:如何實現一個 Virtual DOM 算法 #13
是什么 什么是DOM?DOM 是 JavaScript 操作網頁的接口,全稱為“文檔對象模型”(Document Object Model)。它的作用是將網頁轉為一個 JavaScript 對象,從而可以用腳本進行各種操作(比如增刪內容)。
DOM就是將網頁轉化為一個對象并提供操作這個對象接口(即操作這個對象的方法),所以可以通過DOM對網頁中的元素進行操作。如對某個節點增加屬性,增加孩子,刪除等。
DOM就是網頁里你看得見的對應的某個元素。
舉例說明:如果網頁中有一個表格,表頭是姓名,年級,分數。如果我希望點擊姓名表格就按照字典序排序,點擊年級,按照年級從大到小排序等等操作,那么如果直接去操作DOM的話就很難實現。例如,我們刪除了一個DOM結點,或者新增了一條數據,那么重新進行排序,就會刪除所有DOM然后重新渲染一遍DOM。如果數據很多的話,就會很浪費資源,影響網頁的性能,可能會卡頓。
為什么會卡頓呢?是因為一個節點元素實際上包含很多屬性方法,創建一個DOM就包含上百條數據,加載上綁定的事件等。性能開銷很大。
我可以根據DOM結構,然后自己創建一個數據結構,自己創建的這個DOM和真實的DOM 是一一映射的。然后我們操作的時候就操作自己的數據結構,數據量很小,不管進行排序或其他處理都會很迅速。處理好之后,再根據這個數據結構把它變為真實的DOM。
即我們用虛擬的DOM結構替換需要處理的DOM結構,對虛擬的DOM 進行操作之后再進行渲染,就成為了真實的數據。
這樣的好處是如果我們需要對DOM結點進行改變,那么我們只需要查看我們自己創建的虛擬DOM,看看其中哪條數據發生了改變,然后修改虛擬DOM,并把它渲染成真實的數據即可。例如我們本來就有500條數據,然后需要添加10條,那么我們只添加10條新的虛擬DOM,然后再把這10條虛擬DOM轉化為真實的DOM即可,不需要從新吧510跳全部重新渲染一遍。這樣性能會提升。
所謂的虛擬DOM實際上就是我們根據真實的DOM結構,創建一個和真實DOM映射的一個數據結構,然后對數據結構進行操作,最后把這個數據結構反映到真實的DOM中。
我們可以在邏輯上把這個數據結構渲染成真實的DOM,他在數據結構上和真實DOM是差不多的
舉個例子:我們可以使用一個數據結構來映射DOM(用JS對象模擬DOM樹):
我們將節點用一個對象來表示,tag屬性表示他的種類,children屬性表示他擁有的兒子數組。那么:
這就是虛擬的DOM,體積很輕量,沒有所有的屬性和接口!用來操作的時候不需要耗費很高的性能。
代碼如下:
JS Bin
let nodesData = { tag: "div", children: [ { tag: "p", children: [ { tag: "span", children: [ { tag: "#text", text: "xiedaimala.com" } ] } ] }, { tag: "span", children: [ { tag: "#text", text: "jirengu.com" } ] } ] }
接下來我們只需要將這個虛擬的DOM渲染成真實的DOM就可以了,例如寫一個函數來渲染DOM。
function createElement (data){ }
舉例說明虛擬DOM的作用:
這時我們修改了DOM,例如我們將div中的p標簽中span標簽的內容由xiedaimala.com修改為baidu.com,那么我們只需要修改我們創建的數據結構中的span標簽text那個屬性,然后將原來內存中的nodesData與修改后的nodesData2進行比較。例如:
let nodesData2 = { tag: "div", children: [ { tag: "p", children: [ { tag: "span", children: [ { tag: "#text", text: "baidu.com"http://這里變了 } ] } ] }, { tag: "span", children: [ { tag: "#text", text: "jirengu.com" } ] } ] }
發現span標簽的text內容改變了,那么我們在修改真實DOM的時候不需要把所有的真實DOM的很多屬性和方法都檢索一遍,然后重新渲染一遍,而只需要重新渲染在虛擬DOM中比較出來的修改的部分,即只需要重新渲染text部分就可以了。
以下為
深度剖析:如何實現一個 Virtual DOM 算法 #13文章中的一段解釋
既然原來 DOM 樹的信息都可以用 JavaScript 對象來表示,反過來,你就可以根據這個用 JavaScript 對象表示的樹結構來構建一棵真正的DOM樹。如何實現之前的章節所說的,狀態變更->重新渲染整個視圖的方式可以稍微修改一下:用 JavaScript 對象表示 DOM 信息和結構,當狀態變更的時候,重新渲染這個 JavaScript 的對象結構。當然這樣做其實沒什么卵用,因為真正的頁面其實沒有改變。
但是可以用新渲染的對象樹去和舊的樹進行對比,記錄這兩棵樹差異。記錄下來的不同就是我們需要對頁面真正的 DOM 操作,然后把它們應用在真正的 DOM 樹上,頁面就變更了。這樣就可以做到:視圖的結構確實是整個全新渲染了,但是最后操作DOM的時候確實只變更有不同的地方。
簡單實現:
虛擬DOM渲染為真實DOM/** * @author ruoyu * @description 虛擬 DOM Demo * @todo 暫時不考慮復雜情況 */ 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 } } /*以上為ES6寫法,改為ES5寫法為:*/ /******* function VNode() { this.tag = tag this.text = text this.children = children } VNode.prototype.render = function() { 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 } ****** 這幾句代碼的作用是將js對象表示的虛擬DOM渲染為真實的DOM */ /*這個函數的作用是傳入幾個參數,然后返回對象*/ function v(tag, children, text) { if(typeof children === "string") { text = children children = [] } return new VNode(tag, children, text) } /* 這里是js對象虛擬dom的數據結構 let nodesData = { tag: "div", children: [ { tag: "p", children: [ { tag: "span", children: [ { tag: "#text", text: "xiedaimala.com" } ] } ] }, { tag: "span", children: [ { tag: "#text", text: "jirengu.com" } ] } ] } */ /*使用v函數將幾個參數轉化為對象并返回*/ let vNodes = v("div", [ v("p", [ v("span", [ v("#text", "xiedaimala.com") ] ) ] ), v("span", [ v("#text", "jirengu.com") ]) ] ) /*渲染為真實的DOM*/ console.log(vNodes) /*下方有打印的結果*/ console.log(vNodes.render())
我們看一下打印的結果
DOM數據更新以下僅為簡單實現,是為了理解原理,實際上要想做到很完美的虛擬DOM,需要考慮很多
function patchElement(parent, newVNode, oldVNode, index = 0) { if(!oldVNode) {//如果沒有,直接創建新的DOM,例如patchElement(root, vNodes1) parent.appendChild(newVNode.render()) } else if(!newVNode) {//刪除DOM的操作,例如patchElement(root) parent.removeChild(parent.childNodes[index]) } else if(newVNode.tag !== oldVNode.tag || newVNode.text !== oldVNode.text)//替換(修改)DOM操作,例如兩個VNode比較簡單,然后互相比較 { parent.replaceChild(newVNode.render(), parent.childNodes[index]) } else {//遞歸替換孩子DOM,遞歸比較 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", "xiedaimala.com") ] ) ] ), v("span", [ v("#text", "jirengu.com") ]) ] ) let vNodes2 = v("div", [ v("p", [ v("span", [ v("#text", "xiedaimala.com") ] ) ] ), v("span", [ v("#text", "jirengu.coms"), v("#text", "ruoyu") ]) ] ) const root = document.querySelector("#root") patchElement(root, vNodes1)//創建新的DOM, patchElement(root)//刪除DOM的操作 patchElement(root, vNodes2,vNodes1)//替換(修改)DOM操作
以上只是簡單實現!有很多bug
總結問:說說虛擬DOM:
當我們修改真正的DOM樹的時候,因為DOM中元素節點有許多的屬性和方法,當DOM中節點過多時往往需要消耗很大的性能。
解決方法是:使用js對象來表示DOM樹的信息和結構,這個js對象可以構建一個真正的DOM樹。當狀態變更的時候用修改后的新渲染的的js對象和舊的虛擬DOM js對象作對比,記錄著兩棵樹的差異。把差別反映到真實的DOM 結構上最后操作真正的DOM的時候只操作有差異的部分就可以了
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/98060.html
摘要:為此也做了一些學習簡單的侃一侃虛擬到底是什么虛擬詳解二什么是虛擬虛擬首次產生是框架最先提出和使用的,其卓越的性能很快得到廣大開發者的認可,繼之后也在其核心引入了虛擬的概念。所謂的虛擬到底是什么也就是通過語言來描述一段代碼。 隨著Vue和React的風聲水起,伴隨著諸多框架的成長,虛擬DOM漸漸成了我們經常議論和討論的話題。什么是虛擬DOM,虛擬DOM是如何渲染的,那么Vue的虛擬Dom...
摘要:的一個突出特點是擁有極速地渲染性能。該功能依靠的就是研發團隊弄出的虛擬機制以及其獨特的算法。在的算法下,在同一位置對比前后節點只要發現不同,就會刪除操作前的節點包括其子節點,替換為操作后的節點。 React的一個突出特點是擁有極速地渲染性能。該功能依靠的就是facebook研發團隊弄出的虛擬dom機制以及其獨特的diff算法。下面簡單解釋一下react虛擬dom機制和diff算法的實現...
摘要:第一篇文章中主要講解了虛擬基本實現,簡單的回顧一下,虛擬是使用數據描述的一段虛擬節點樹,通過函數生成其真實節點。并添加到其對應的元素容器中。在創建真實節點的同時并為其注冊事件并添加一些附屬屬性。 第一篇文章中主要講解了虛擬DOM基本實現,簡單的回顧一下,虛擬DOM是使用json數據描述的一段虛擬Node節點樹,通過render函數生成其真實DOM節點。并添加到其對應的元素容器中。在創建...
閱讀 2386·2021-09-22 16:01
閱讀 3153·2021-09-22 15:41
閱讀 1171·2021-08-30 09:48
閱讀 490·2019-08-30 15:52
閱讀 3324·2019-08-30 13:57
閱讀 1713·2019-08-30 13:55
閱讀 3649·2019-08-30 11:25
閱讀 757·2019-08-29 17:25