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