成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

你不知的DOM編程

warnerwu / 2895人閱讀

摘要:思路合并所有改變?nèi)缓笠淮涡蕴幚硎褂脤傩孕薷念惷啃薷漠?dāng)你需要對(duì)元素進(jìn)行一系列操作的時(shí)候,不妨按照如下步驟使元素脫離文檔流對(duì)其應(yīng)用多重改變把元素帶回文檔中上面的這一套組合拳中,第一步和第三部分別會(huì)觸發(fā)一次重排。

前言:隨著vue,react, angular的流行,可能現(xiàn)在我們不必經(jīng)常的操作DOM,三大框架在副交互的操作中發(fā)揮著極大地優(yōu)勢(shì)。因?yàn)槲覀冎烙媚_本對(duì)DOM的操作非常昂貴,本文主要探討常規(guī)的DOM操作中你可能不知道的知識(shí)。

瀏覽器中的DOM

首先,我們來(lái)了解一下什么是DOM,他為什么慢?

DOM,天生就慢

文檔對(duì)象模型 (DOM)是 W3C(萬(wàn)維網(wǎng)聯(lián)盟)的標(biāo)準(zhǔn),是一個(gè)獨(dú)立于語(yǔ)言的,用于操作XML和HTML文檔的程序接口。在瀏覽器中,主要和HTML文檔打交道,盡管DOM是個(gè)與語(yǔ)言無(wú)關(guān)的API,但是它在瀏覽器中的接口卻是用JS實(shí)現(xiàn)的。但是通常瀏覽器會(huì)把DOM和JS分開(kāi)來(lái)實(shí)現(xiàn),比如Chrome中的DOM實(shí)現(xiàn)為webkit中的webCore,但js引擎是Google自己研發(fā)的V8。既然分開(kāi)了,一旦兩者需要產(chǎn)生連接,就要付出代價(jià)。

DOM 訪問(wèn)與修改

前面說(shuō)到JS訪問(wèn)DOM會(huì)產(chǎn)生而性能上的消耗,如果去修改DOM元素則代價(jià)更為昂貴,因?yàn)樗鼤?huì)導(dǎo)致瀏覽器重新計(jì)算頁(yè)面的幾何變化。 來(lái)看兩端段代碼:

第一段代碼定義了一個(gè)普通的變量,進(jìn)行循環(huán)累加,執(zhí)行事件幾乎為。第二段代碼,每次循環(huán)會(huì)訪問(wèn)兩次特定的元素:第一次讀取這個(gè)元素的innerHTML屬性,第二次重寫它??梢钥吹剿膱?zhí)行時(shí)間將近2.8s,這段腳本會(huì)一直阻塞后續(xù)的執(zhí)行。
看清楚了這一點(diǎn),不難得到一個(gè)效率更高的版本:

用一個(gè)局部變量包層每次更新后的內(nèi)容,等待循環(huán)結(jié)束后,一次性的寫入頁(yè)面(盡可能的把更多的工作交給js的部分來(lái)做)??梢钥吹娇炝私?000倍。
顯而易見(jiàn)。訪問(wèn)DOM的次數(shù)越多,代碼的運(yùn)行速度越慢,因此,通用的經(jīng)驗(yàn)做法是:減少訪問(wèn)DOM的次數(shù),把運(yùn)算盡量留給JS處理。這也是Vue或者React為什么要設(shè)計(jì)virtual dom 的初衷之一:把負(fù)責(zé)的DOM模型映射成JS對(duì)象,不去直接操作DOM而是通過(guò)操作JS對(duì)象,最后再進(jìn)行 innerHtml 或者 append。

HTML 集合

我們先來(lái)看一段代碼:

var alldivs = document.getElementsByTagName("div");  
for (var i = 0; i < alldivs.length; i++){  
    document.body.appendChild(document.createElement("div"));  
}

乍一看,這段代碼只是單純的把頁(yè)面中的div數(shù)量翻倍:遍歷所有的div,每次創(chuàng)建一個(gè)新的div并創(chuàng)建到添加到body中。
但事實(shí)上,這是一個(gè)死循環(huán):因?yàn)檠h(huán)的退出條件alldivs.length在每一次循環(huán)結(jié)束后都會(huì)增加,因?yàn)檫@個(gè)HTML元素集合反映的是底層文檔元素的實(shí)時(shí)狀態(tài)。 類似于下面的HTML集合其實(shí)都會(huì)存在這樣的問(wèn)題:

document.getElementsByTagName()

document.getElementsByClassName()

document.getElementsByName()
....

其次上面的代碼也會(huì)存在一個(gè)性能問(wèn)題,就是每次都需要訪問(wèn)DOM對(duì)象的length屬性。其實(shí)我們也可以用一個(gè)變量緩存起來(lái)對(duì)象的length屬性:

var len = document.getElementsByTagName("div").length;  
for (var i = 0; i < len; i++){  
    document.body.appendChild(document.createElement("div"));  
}
重繪與重排

瀏覽器用來(lái)顯示頁(yè)面的所有“組件”,有:HTML標(biāo)簽、js、css、圖片——之后會(huì)解析并生成兩個(gè)內(nèi)部的數(shù)據(jù)結(jié)構(gòu):

DOM樹(shù)(表示頁(yè)面結(jié)構(gòu))
渲染樹(shù)(表示DOM節(jié)點(diǎn)應(yīng)該如何表示)
DOM樹(shù)中的每一個(gè)需要顯示的節(jié)點(diǎn)在渲染樹(shù)中至少存在一個(gè)對(duì)應(yīng)的節(jié)點(diǎn)。
渲染樹(shù)中的節(jié)點(diǎn)被稱為“幀(frames)”或“盒(boxes)”,符合css盒模型的定義,理解頁(yè)面元素為一個(gè)具有padding、margin、borders和position的盒子。
一旦渲染樹(shù)構(gòu)建完成,瀏覽器就開(kāi)始顯示頁(yè)面元素,這個(gè)過(guò)程稱為繪制(paint)。

當(dāng)DOM的變化影響了元素的幾何屬性(寬、高)——比如改變改變了邊框的寬度或者給一個(gè)段落增加一些文字導(dǎo)致其行數(shù)的增加——瀏覽器就需要重新計(jì)算元素的幾何屬性,同樣,頁(yè)面中其他元素的幾何屬性和位置也會(huì)因此受到影響。
瀏覽器會(huì)使渲染樹(shù)中收到影響的部分消失,重新構(gòu)建渲染樹(shù),這個(gè)過(guò)程稱為“重排(reflow)”。重排完成之后,瀏覽器會(huì)重新將受到影響的部分繪制到瀏覽器中,這個(gè)過(guò)程稱之為“重繪(repaint)”。

如果改變的不是元素的幾何屬性,如:改變?cè)氐谋尘邦伾?,不?huì)發(fā)生重排,只會(huì)發(fā)生一次重繪,因?yàn)樵氐牟季植](méi)有改變。
不管是重繪還是重排,都是代價(jià)昂貴的操作,它們會(huì)導(dǎo)致web應(yīng)用程序的UI反應(yīng)遲鈍,應(yīng)當(dāng)盡可能的減少這類過(guò)程的發(fā)生。
重排何時(shí)發(fā)生?

添加或刪除可見(jiàn)的DOM元素

元素位置的改變

元素尺寸的改變(padding、margin、border、height、width)

內(nèi)容改變(文本改變或圖片尺寸改變)

頁(yè)面渲染器初始化

瀏覽器窗口尺寸改變

滾動(dòng)條的出現(xiàn)(會(huì)觸發(fā)整個(gè)頁(yè)面的重排)

最小化重繪和重排

改變樣式

一個(gè)栗子:

var el = document.getElementById("mydiv");  
el.style.borderLeft = "1px";  
el.style.borderRight = "2px";  
el.style.padding = "5px";  

示例中,元素的三個(gè)樣式被改變,而且每一個(gè)都會(huì)影響元素的幾何結(jié)構(gòu)。在最糟糕的情況下,這段代碼會(huì)觸發(fā)三次重排(大部分現(xiàn)代瀏覽器為此做了優(yōu)化,只會(huì)觸發(fā)一次重排)。從另一個(gè)角度看,這段代碼四次訪問(wèn)DOM,可以被優(yōu)化。

var el = document.getElementById("mydiv");  
//思路:合并所有改變?nèi)缓笠淮涡蕴幚? 
//method_1:使用cssText屬性  
el.style.cssText = "border-left: 1px; border-right: 2px; padding: 5px";  
  
//method_2:修改類名  
el.className = "anotherClass";  
批量修改DOM

當(dāng)你需要對(duì)DOM元素進(jìn)行一系列操作的時(shí)候,不妨按照如下步驟:

使元素脫離文檔流

對(duì)其應(yīng)用多重改變

把元素帶回文檔中

上面的這一套組合拳中,第一步和第三部分別會(huì)觸發(fā)一次重排。但是如果你忽略了這兩個(gè)步驟,那么在第二步所產(chǎn)生的任何修改都會(huì)觸發(fā)一次重排。

在此安利三種可以使DOM元素脫離文檔流的方法:

隱藏元素

使用文檔片段(document fragment)在當(dāng)前DOM之外構(gòu)建一個(gè)子樹(shù),再把它拷貝回文檔

將原始元素拷貝到一個(gè)脫離文檔的節(jié)點(diǎn)中,修改副本,完成后再替換原始元素

讓動(dòng)畫元素脫離文檔流

一般情況下,重排只影響渲染樹(shù)中的一小部分,但也可能影響很大的一部分,甚至是整個(gè)渲染樹(shù)。
瀏覽器所需的重排次數(shù)越少,應(yīng)用程序的響應(yīng)速度也就越快。
想象這樣一種情況,頁(yè)面的底部有一個(gè)動(dòng)畫,會(huì)推移頁(yè)面整個(gè)余下的部分,這將是一次代價(jià)昂貴的大規(guī)模重排!用戶也勢(shì)必會(huì)感覺(jué)到頁(yè)面一卡一卡的。
因此,使用以下步驟可以避免頁(yè)面中的大部分重排:

使用絕對(duì)定位讓頁(yè)面上的動(dòng)畫元素脫離文檔流

動(dòng)畫展示階段

動(dòng)畫結(jié)束時(shí),將元素恢復(fù)定位。

IE的:hover

從IE7開(kāi)始,IE允許在任何元素上使用:hover這個(gè)css選擇器。
然而,如果你有大量元素使用了:hover,你會(huì)發(fā)現(xiàn),賊喇慢!

關(guān)于

作者:monkeyWang

本人主頁(yè):https://monkeywangs.github.io/

微信公眾號(hào):會(huì)不定期推送前端技術(shù)文章,歡迎關(guān)注

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/51478.html

相關(guān)文章

  • 不知DOM編程

    摘要:思路合并所有改變?nèi)缓笠淮涡蕴幚硎褂脤傩孕薷念惷啃薷漠?dāng)你需要對(duì)元素進(jìn)行一系列操作的時(shí)候,不妨按照如下步驟使元素脫離文檔流對(duì)其應(yīng)用多重改變把元素帶回文檔中上面的這一套組合拳中,第一步和第三部分別會(huì)觸發(fā)一次重排。 前言:隨著vue,react, angular的流行,可能現(xiàn)在我們不必經(jīng)常的操作DOM,三大框架在副交互的操作中發(fā)揮著極大地優(yōu)勢(shì)。因?yàn)槲覀冎烙媚_本對(duì)DOM的操作非常昂貴,本文...

    Anshiii 評(píng)論0 收藏0
  • gitbook: 前端好書推薦

    摘要:它大致概述并討論了前端工程的實(shí)踐如何學(xué)習(xí)它,以及在年實(shí)踐時(shí)使用什么工具。目的是每年發(fā)布一次內(nèi)容更新。前端實(shí)踐第一部分廣泛描述了前端工程的實(shí)踐。對(duì)大多數(shù)人來(lái)說(shuō),函數(shù)式編程看起來(lái)更加自然。 1 Front-End Developer Handbook 2017 地址:https://frontendmasters.com/b... 這是任何人都可以用來(lái)了解前端開(kāi)發(fā)實(shí)踐的指南。它大致概述并...

    Ali_ 評(píng)論0 收藏0
  • gitbook: 前端好書推薦

    摘要:它大致概述并討論了前端工程的實(shí)踐如何學(xué)習(xí)它,以及在年實(shí)踐時(shí)使用什么工具。目的是每年發(fā)布一次內(nèi)容更新。前端實(shí)踐第一部分廣泛描述了前端工程的實(shí)踐。對(duì)大多數(shù)人來(lái)說(shuō),函數(shù)式編程看起來(lái)更加自然。 1 Front-End Developer Handbook 2017 地址:https://frontendmasters.com/b... 這是任何人都可以用來(lái)了解前端開(kāi)發(fā)實(shí)踐的指南。它大致概述并...

    CocoaChina 評(píng)論0 收藏0
  • gitbook: 前端好書推薦

    摘要:它大致概述并討論了前端工程的實(shí)踐如何學(xué)習(xí)它,以及在年實(shí)踐時(shí)使用什么工具。目的是每年發(fā)布一次內(nèi)容更新。前端實(shí)踐第一部分廣泛描述了前端工程的實(shí)踐。對(duì)大多數(shù)人來(lái)說(shuō),函數(shù)式編程看起來(lái)更加自然。 1 Front-End Developer Handbook 2017 地址:https://frontendmasters.com/b... 這是任何人都可以用來(lái)了解前端開(kāi)發(fā)實(shí)踐的指南。它大致概述并...

    Warren 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<