一、vdom是什么?
vdom是虛擬DOM(Virtual DOM)的簡稱,指的是用JS模擬的DOM結(jié)構(gòu),將DOM變化的對比放在JS層來做。換而言之,vdom就是JS對象。
如下DOM結(jié)構(gòu):
<ul?id="list"> ?<li>Item1</li> ?<li>Item2</li> </ul> 復(fù)制代碼
映射成虛擬DOM就是這樣:
{ ?tag:?"ul", ?attrs:?{ ?id:?"list" ?}, ?children:?[ ?{ ?tag:?"li", ?attrs:?{?className:?"item"?}, ?children:?["Item1"] ?},?{ ?tag:?"li", ?attrs:?{?className:?"item"?}, ?children:?["Item2"] ?} ?] }? 復(fù)制代碼
二、為什么要用vdom?
現(xiàn)在有一個場景,實現(xiàn)以下需求:
[ ?{ ?name:?"張三", ?age:?"20", ?address:?"北京" ?}, ?{ ?name:?"李四", ?age:?"21", ?address:?"武漢" ?}, ?{ ?name:?"王五", ?age:?"22", ?address:?"杭州" ?}, ] 復(fù)制代碼
將該數(shù)據(jù)展示成一個表格,并且隨便修改一個信息,表格也跟著修改。 用jQuery實現(xiàn)如下:
<!DOCTYPE?html> <html> <head> ?<meta?charset="UTF-8"> ?<meta?name="viewport"?content="width=device-width,?initial-scale=1.0"> ?<meta?http-equiv="X-UA-Compatible"?content="ie=edge"> ?<title>Document</title> </head> <body> ?<div?id="container"></div> ?<button?id="btn-change">改變</button> ?<script?src="https://cdn.bootcss.com/jquery/3.2.0/jquery.js"></script> ?<script> ?const?data?=?[{ ?name:?"張三", ?age:?"20", ?address:?"北京" ?}, ?{ ?name:?"李四", ?age:?"21", ?address:?"武漢" ?}, ?{ ?name:?"王五", ?age:?"22", ?address:?"杭州" ?}, ?]; ?//渲染函數(shù) ?function?render(data)?{ ?const?$container?=?$('#container'); ?$container.html(''); ?const?$table?=?$('<table>'); ?//?重繪一次 ?$table.append($('<tr><td>name</td><td>age</td><td>address</td></tr>')); ?data.forEach(item?=>?{ ?//每次進(jìn)入都重繪 ?$table.append($(`<tr><td>${item.name}</td><td>${item.age}</td><td>${item.address}</td></tr>`)) ?}) ?$container.append($table); ?} ? ?$('#btn-change').click(function?()?{ ?data[1].age?=?30; ?data[2].address?=?'深圳'; ?render(data); ?}); ?</script> </body> </html> 復(fù)制代碼
這樣點(diǎn)擊按鈕,會有相應(yīng)的視圖變化,但是你審查以下元素,每次改動之后,table標(biāo)簽都得重新創(chuàng)建,也就是說table下面的每一個欄目,不管是數(shù)據(jù)是否和原來一樣,都得重新渲染,這并不是理想中的情況,當(dāng)其中的一欄數(shù)據(jù)和原來一樣,我們希望這一欄不要重新渲染,因為DOM重繪相當(dāng)消耗瀏覽器性能。
因此我們采用JS對象模擬的方法,將DOM的比對操作放在JS層,減少瀏覽器不必要的重繪,提高效率。
當(dāng)然有人說虛擬DOM并不比真實的DOM快,其實也是有道理的。當(dāng)上述table中的每一條數(shù)據(jù)都改變時,顯然真實的DOM操作更快,因為虛擬DOM還存在js中diff算法的比對過程。所以,上述性能優(yōu)勢僅僅適用于大量數(shù)據(jù)的渲染并且改變的數(shù)據(jù)只是一小部分的情況。
虛擬DOM更加優(yōu)秀的地方在于:
1、它打開了函數(shù)式的UI編程的大門,即UI = f(data)這種構(gòu)建UI的方式。
2、可以將JS對象渲染到瀏覽器DOM以外的環(huán)境中,也就是支持了跨平臺開發(fā),比如ReactNative。
另外大家可以參考尤大的一些回答: www.zhihu.com/question/31…
三、使用snabbdom實現(xiàn)vdom
snabbdom地址:github.com/snabbdom/sn…
這是一個簡易的實現(xiàn)vdom功能的庫,相比vue、react,對于vdom這塊更加簡易,適合我們學(xué)習(xí)vdom。vdom里面有兩個核心的api,一個是h函數(shù),一個是patch函數(shù),前者用來生成vdom對象,后者的功能在于做虛擬dom的比對和將vdom掛載到真實DOM上。
簡單介紹一下這兩個函數(shù)的用法:
h('標(biāo)簽名', {屬性}, [子元素])
h('標(biāo)簽名', {屬性}, [文本])
patch(container, vnode) container為容器DOM元素
patch(vnode, newVnode)
現(xiàn)在我們就來用snabbdom重寫一下剛才的例子:
<!DOCTYPE?html> <html> <head> ?<meta?charset="UTF-8"> ?<meta?name="viewport"?content="width=device-width,?initial-scale=1.0"> ?<meta?http-equiv="X-UA-Compatible"?content="ie=edge"> ?<title>Document</title> </head> <body> ?<div?id="container"></div> ?<button?id="btn-change">改變</button> ?<script?src="https://cdn.bootcss.com/snabbdom/0.7.3/snabbdom.js"></script> ?<script?src="https://cdn.bootcss.com/snabbdom/0.7.3/snabbdom-class.js"></script> ?<script?src="https://cdn.bootcss.com/snabbdom/0.7.3/snabbdom-props.js"></script> ?<script?src="https://cdn.bootcss.com/snabbdom/0.7.3/snabbdom-style.js"></script> ?<script?src="https://cdn.bootcss.com/snabbdom/0.7.3/snabbdom-eventlisteners.min.js"></script> ?<script?src="https://cdn.bootcss.com/snabbdom/0.7.3/h.js"></script> ?<script> ?let?snabbdom?=?window.snabbdom; ?//?定義patch ?let?patch?=?snabbdom.init([ ?snabbdom_class, ?snabbdom_props, ?snabbdom_style, ?snabbdom_eventlisteners ?]); ?//定義h ?let?h?=?snabbdom.h; ?const?data?=?[{ ?name:?"張三", ?age:?"20", ?address:?"北京" ?}, ?{ ?name:?"李四", ?age:?"21", ?address:?"武漢" ?}, ?{ ?name:?"王五", ?age:?"22", ?address:?"杭州" ?}, ?]; ?data.unshift({name:?"姓名",?age:?"年齡",?address:?"地址"}); ?let?container?=?document.getElementById('container'); ?let?vnode; ?const?render?=?(data)?=>?{ ?let?newVnode?=?h('table',?{},?data.map(item?=>?{? ?let?tds?=?[]; ?for(let?i?in?item)?{ ?if(item.hasOwnProperty(i))?{ ?tds.push(h('td',?{},?item[i]?+?'')); ?} ?} ?return?h('tr',?{},?tds); ?})); ?if(vnode)?{ ?patch(vnode,?newVnode); ?}?else?{ ?patch(container,?newVnode); ?} ?vnode?=?newVnode; ?} ?render(data); ?let?btnChnage?=?document.getElementById('btn-change'); ?btnChnage.addEventListener('click',?function()?{ ?data[1].age?=?30; ?data[2].address?=?"深圳"; ?//re-render ?render(data); ?}) ?</script> </body> </html> 復(fù)制代碼
再進(jìn)入頁面:
你會發(fā)現(xiàn),只有改變的欄目才閃爍,也就是進(jìn)行重繪,數(shù)據(jù)沒有改變的欄目還是保持原樣,這樣就大大節(jié)省了瀏覽器重新渲染的開銷。四、diff算法
1、什么是diff算法?
所謂diff算法,就是用來找出兩段文本之間的差異的一種算法。
作為一個前端,大家經(jīng)常會聽到diff算法這個詞,其實diff并不是前端原創(chuàng)的算法,其實這一個算法早已在linux的diff命令中有所體現(xiàn),并且大家常用的git diff也是運(yùn)用的diff算法。
2、vdom為什么用diff算法
DOM操作是非常昂貴的,因此我們需要盡量地減少DOM操作。這就需要找出本次DOM必須更新的節(jié)點(diǎn)來更新,其他的不更新,這個找出的過程,就需要應(yīng)用diff算法。
3、vdom中diff算法的簡易實現(xiàn)
以下代碼只是幫助大家理解diff算法的原理和流程,不可用于生產(chǎn)環(huán)境。
將vdom轉(zhuǎn)化為真實dom:
const?createElement?=?(vnode)?=>?{ ?let?tag?=?vnode.tag; ?let?attrs?=?vnode.attrs?||?{}; ?let?children?=?vnode.children?||?[]; ?if(!tag)?{ ?return?null; ?} ?//創(chuàng)建元素 ?let?elem?=?document.createElement(tag); ?//屬性 ?let?attrName; ?for?(attrName?in?attrs)?{ ?if(attrs.hasOwnProperty(attrName))?{ ?elem.setAttribute(attrName,?attrs[attrName]); ?} ?} ?//子元素 ?children.forEach(childVnode?=>?{ ?//給elem添加子元素 ?elem.appendChild(createElement(childVnode)); ?}) ?//返回真實的dom元素 ?return?elem; } 復(fù)制代碼
用簡易diff算法做更新操作:
function?updateChildren(vnode,?newVnode)?{ ?let?children?=?vnode.children?||?[]; ?let?newChildren?=?newVnode.children?||?[]; ?children.forEach((childVnode,?index)?=>?{ ?let?newChildVNode?=?newChildren[index]; ?if(childVnode.tag?===?newChildVNode.tag)?{ ?//深層次對比,?遞歸過程 ?updateChildren(childVnode,?newChildVNode); ?}?else?{ ?//替換 ?replaceNode(childVnode,?newChildVNode); ?} ?}) } 復(fù)制代碼
參考資料:
知乎尤雨溪回答
揭秘一線互聯(lián)網(wǎng)企業(yè) 前端JavaScript高級面試
前端進(jìn)階與面試指南
另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務(wù)器15元起步,三天無理由+7*72小時售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡單易用、服務(wù)可用性高、性價比高”等特點(diǎn)與優(yōu)勢,專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場景需求。
本文題目:面試官問:如何理解VirtualDOM?-創(chuàng)新互聯(lián)
網(wǎng)頁路徑:http://www.chinadenli.net/article26/dceccg.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供用戶體驗、動態(tài)網(wǎng)站、關(guān)鍵詞優(yōu)化、營銷型網(wǎng)站建設(shè)、App設(shè)計、虛擬主機(jī)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容