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

資訊專欄INFORMATION COLUMN

你不知的DOM編程

Anshiii / 706人閱讀

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

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

瀏覽器中的DOM

首先,我們來了解一下什么是DOM,他為什么慢?

DOM,天生就慢

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

DOM 訪問與修改

前面說到JS訪問DOM會產(chǎn)生而性能上的消耗,如果去修改DOM元素則代價更為昂貴,因為它會導(dǎo)致瀏覽器重新計算頁面的幾何變化。 來看兩端段代碼:

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

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

HTML 集合

我們先來看一段代碼:

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

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

document.getElementsByTagName()

document.getElementsByClassName()

document.getElementsByName()
....

其次上面的代碼也會存在一個性能問題,就是每次都需要訪問DOM對象的length屬性。其實我們也可以用一個變量緩存起來對象的length屬性:

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

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

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

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

如果改變的不是元素的幾何屬性,如:改變元素的背景顏色,不會發(fā)生重排,只會發(fā)生一次重繪,因為元素的布局并沒有改變。
不管是重繪還是重排,都是代價昂貴的操作,它們會導(dǎo)致web應(yīng)用程序的UI反應(yīng)遲鈍,應(yīng)當(dāng)盡可能的減少這類過程的發(fā)生。
重排何時發(fā)生?

添加或刪除可見的DOM元素

元素位置的改變

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

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

頁面渲染器初始化

瀏覽器窗口尺寸改變

滾動條的出現(xiàn)(會觸發(fā)整個頁面的重排)

最小化重繪和重排

改變樣式

一個栗子:

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

示例中,元素的三個樣式被改變,而且每一個都會影響元素的幾何結(jié)構(gòu)。在最糟糕的情況下,這段代碼會觸發(fā)三次重排(大部分現(xiàn)代瀏覽器為此做了優(yōu)化,只會觸發(fā)一次重排)。從另一個角度看,這段代碼四次訪問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)你需要對DOM元素進(jìn)行一系列操作的時候,不妨按照如下步驟:

使元素脫離文檔流

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

把元素帶回文檔中

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

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

隱藏元素

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

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

讓動畫元素脫離文檔流

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

使用絕對定位讓頁面上的動畫元素脫離文檔流

動畫展示階段

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

IE的:hover

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

關(guān)于

作者:monkeyWang

本人主頁:https://monkeywangs.github.io/

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

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

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

相關(guān)文章

  • 不知DOM編程

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

    warnerwu 評論0 收藏0
  • gitbook: 前端好書推薦

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

    Ali_ 評論0 收藏0
  • gitbook: 前端好書推薦

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

    CocoaChina 評論0 收藏0
  • gitbook: 前端好書推薦

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

    Warren 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<