摘要:使用局部變量來(lái)訪問(wèn)集合元素訪問(wèn)任何類型的,當(dāng)同一個(gè)屬性或者方法被訪問(wèn)同一次以上時(shí),最好使用一個(gè)局部變量緩存該成員。當(dāng)遍歷一個(gè)集合的時(shí)候,第一個(gè)要優(yōu)化的就是將集合引用存儲(chǔ)在局部變量中,并在循環(huán)之外緩存屬性。
減少 DOM 重繪和重排的次數(shù)本文章記錄本人在深入學(xué)習(xí)Javascirpt DOM中看書理解到的一些東西,加深記憶和并且整理記錄下來(lái),方便之后的復(fù)習(xí)。
簡(jiǎn)單了解重繪和重排
在渲染dom樹中為每個(gè)需要顯示的dom樹節(jié)點(diǎn)存放至少一個(gè)節(jié)點(diǎn),隱藏的dom元素在渲染樹中沒(méi)有對(duì)應(yīng)的節(jié)點(diǎn)。然后將頁(yè)面的元素看作一個(gè)具有填、邊距、邊框和位置的盒子,也就是經(jīng)常提到的盒模型。如果dom樹和渲染樹構(gòu)造完畢,瀏覽器就會(huì)顯示或者說(shuō)是繪制頁(yè)面的上的元素了。
當(dāng)dom改變影響了元素的幾何屬性(寬和高)時(shí)候,如改變邊距寬度或者在段落中添加文字將發(fā)生一系列后續(xù)動(dòng)作,瀏覽器就會(huì)重新計(jì)算元素的幾何屬性,而且其他元素的幾何屬性和位置也會(huì)因此收到影響。瀏覽器是渲染樹上受到影響的部分失效,然后重構(gòu)渲染樹,這個(gè)過(guò)程叫做重排。當(dāng)重排完畢后,瀏覽器會(huì)在繪制進(jìn)程中重新繪制屏幕上受到影響的部分。
有一些屬性修改是不會(huì)影響幾何屬性的,例如:改變一個(gè)元素的背景色不會(huì)影響它的高度和寬度。這種情況,只需要重繪,因?yàn)樵氐牟季譀](méi)有發(fā)生變化。
什么情況下會(huì)觸發(fā)重繪和重排
添加或刪除可見的dom元素。
元素的位置改變。
元素的尺寸改變。
內(nèi)容改變,如文本改變或圖片被另一個(gè)尺寸的圖片所代替。
最初的頁(yè)面渲染。
瀏覽器窗口大小改變。
某一些改變可能導(dǎo)致重排整個(gè)頁(yè)面,例如:當(dāng)一個(gè)滾動(dòng)條出現(xiàn)時(shí)。
如何減少重排和重繪
由于重排與重繪的代價(jià)較高,提高程序響應(yīng)速度是一個(gè)好策略是減少此類的操作發(fā)生的機(jī)會(huì)。
例1,應(yīng)該將多個(gè)dom風(fēng)格改變后合并到一個(gè)批次中一次性執(zhí)行。
var el = document.getElementById("demo"); el.style.broderLeft = "1px"; el.style.broderRight = "2px"; el.style.padding = "5px";
上面的代碼改變了3個(gè)樣式屬性,每次改變都會(huì)影響元素的幾何屬性。導(dǎo)致瀏覽器重排了3次?,F(xiàn)在大多數(shù)瀏覽器都優(yōu)化了這種情況,只進(jìn)行一次重排,但是在舊版本的瀏覽器中,效率非常的底下。
實(shí)現(xiàn)相同效果但效率更高的方法:將所有改變合并在一起執(zhí)行,只修改dom一次。使用cssText。
el.style.cssText = "border-left: 1px;border-right: 2px;padding: 5px";
還有另外一種優(yōu)化方式就是修改css的類名稱,而不是修改元素的內(nèi)聯(lián)風(fēng)格代碼。這種方法適合用于那些風(fēng)格不依賴于運(yùn)行邏輯且不需要計(jì)算的情況下。改變后的css類名稱更加清晰,更便于維護(hù)。
el.className += " active";
例2,當(dāng)需要對(duì)dom元素進(jìn)行多次的修改時(shí),可以通過(guò)以下步驟減少重繪和重排次數(shù)。
從文檔流中摘除該元素。
對(duì)其應(yīng)用多重改變。
將元素帶回文檔中。
這個(gè)過(guò)程中引發(fā)兩次重排:第1步引發(fā)一次,第3步引發(fā)一次。如果忽略了這兩個(gè)步驟,那么第2步中每次改變都會(huì)引發(fā)一次重排。
經(jīng)歷3步后可以將dom從文檔中摘除:
隱藏元素
使用一個(gè)文檔片斷在一存在dom之外創(chuàng)建一個(gè)子樹,然后將它復(fù)制到文檔。
將原始文檔復(fù)制到一個(gè)脫離文檔的節(jié)點(diǎn)中,修改副本,然后覆蓋原始元素。
避免大部分重排
重排有時(shí)候只影響渲染數(shù)的一小部分,但也能影響一大部分。甚至整個(gè)渲染樹。瀏覽器需要重排ud部分越小。應(yīng)用程序的響應(yīng)速度越快,因此,當(dāng)一個(gè)頁(yè)面頂部的動(dòng)畫推移差不多整個(gè)頁(yè)面時(shí),將引發(fā)巨大的重排動(dòng)作,使用戶感到動(dòng)畫不流暢。渲染數(shù)的大多數(shù)節(jié)點(diǎn)需要重新計(jì)算,這使情況更加糟糕。
以下步驟可以避免大部分頁(yè)面進(jìn)行重排:
使用絕對(duì)定位坐標(biāo)定位頁(yè)面動(dòng)畫元素,使它位于頁(yè)面布局流之外。
啟動(dòng)元素動(dòng)畫,當(dāng)它擴(kuò)大時(shí)候,將會(huì)臨時(shí)覆蓋部頁(yè)面。這是一個(gè)重繪過(guò)程,但是只能影響頁(yè)面一小部分,避免重排以及重繪一大塊也頁(yè)面。
當(dāng)動(dòng)畫結(jié)束時(shí)候,重新定位。
克隆節(jié)點(diǎn)與創(chuàng)建節(jié)點(diǎn)哪個(gè)好使用dom方法更新頁(yè)面內(nèi)容的另一個(gè)方法就是克隆已有的dom元素,而不是創(chuàng)建新的元素。在大多數(shù)瀏覽器上,克隆節(jié)點(diǎn)更有效率,但是提高不是很多。如果用克隆節(jié)點(diǎn)的方法去創(chuàng)建1000行的表格,只創(chuàng)建一次單元格,然后重復(fù)的執(zhí)行復(fù)制操作,這樣會(huì)快一些。
所以說(shuō):克隆節(jié)點(diǎn)與創(chuàng)建節(jié)都差不多,而克隆節(jié)點(diǎn)方法更加適合那些重復(fù)操作同一個(gè)dom元素。
使用 nextSibling 抓取 DOM我們經(jīng)常需要從一個(gè)dom元素開始,操作周圍的元素,或者遞歸迭代所有的子節(jié)點(diǎn)。這時(shí)可以使用childNodes集合或者使用nextSibling獲得每個(gè)元素的兄弟節(jié)點(diǎn)。
var testNextSibling = function(){ var el = documentgetElementById("demo"), ch = el.firstChild, name = ""; do { name = ch.nodeName; } while (ch = ch.nextSibling); return name; }; var testChildNodes = function(){ var el = documentgetElementById("demo"), ch = el.childNodes, len = ch.length, name = ""; for (var i = 0; i < len; i++) { name = ch[i].nodeName; } return name; };
比較上面兩個(gè)功能相同的函數(shù),它們都采用非遞歸方式遍歷一個(gè)元素的子節(jié)點(diǎn)。在不同的瀏覽器下,這兩個(gè)函數(shù)運(yùn)行的時(shí)間都基本相同,但是在IE下,nextSibling表現(xiàn)比childNode好。在IE6下,nextSibling比childNode塊16倍,在IE7下,nextSibling塊105倍。所以說(shuō),在舊版本的IE下使用nextsibling抓取dom是首選,在其他的情況下,主要看個(gè)人和團(tuán)隊(duì)的習(xí)慣決定。
使用局部變量來(lái)訪問(wèn)集合元素訪問(wèn)任何類型的dom,當(dāng)同一個(gè)dom屬性或者方法被訪問(wèn)同一次以上時(shí),最好使用一個(gè)局部變量緩存該dom成員。當(dāng)遍歷一個(gè)集合的時(shí)候,第一個(gè)要優(yōu)化的就是將集合引用存儲(chǔ)在局部變量中,并在循環(huán)之外緩存length屬性。然后,如果在循環(huán)體中多次訪問(wèn)同一個(gè)集合元素,那么使用局部變量緩存它。
// bad var collectionGlobal = function(){ var coll = document.getElementsByTagName("div"), len = coll.length, name = ""; for (var i = 0; i < coll; i++) { name = document.getElementsByTagName("div")[i].nodeName; name = document.getElementsByTagName("div")[i].nodeType; name = document.getElementsByTagName("div")[i].tagName; } return name; }; // good var collectionGlobal = function(){ var coll = document.getElementsByTagName("div"), len = coll.length, name = "", el = null; for (var i = 0; i < coll; i++) { el = coll[i]; name = el.nodeName; name = el.nodeType; name = el.tagName; } return name; };使用 querySelectorAll
使用css選擇器是一個(gè)便捷的確定節(jié)點(diǎn)的方法。許多js庫(kù)提供類似的API,而且最新的瀏覽器提供了一個(gè)名為querySelectorAll的元素瀏覽器dom函數(shù)。顯然這種方法比使用js和dom迭代并縮小元素列表的方法要快。
var el = document.querySelectorAll("#demo a");
當(dāng)需要聯(lián)合查詢的時(shí)候,使用querySelectorAll方法更加的便利。例如,在頁(yè)面中,一些div元素的class名稱是demo1,另一些class名稱是demo2,可以使用querySelectorAll一次性獲得這兩類節(jié)點(diǎn)。
var el = document.querySelectorAll(".demo1, .demo2");
如果瀏覽器支持querySelectorAll方法的話,那么最好就使用它。。還有另一個(gè)函數(shù)querySelector獲取節(jié)點(diǎn),它可以返回符合查詢條件的第一個(gè)節(jié)點(diǎn)。
使用 DOM 結(jié)構(gòu)樹托管事件一個(gè)簡(jiǎn)單而優(yōu)雅的處理dom事件的技術(shù)是事件托管(事件代理)。它基于這樣一個(gè)事實(shí):事件逐層冒泡總能被父級(jí)捕獲。采用事件托管技術(shù)后,只需要在一個(gè)包裝元素上連接一個(gè)句柄,用與處理子元素發(fā)生的所有事件。
捕獲
達(dá)到目標(biāo)
冒泡
因?yàn)?b>IE不支持事件捕獲,所以只要實(shí)現(xiàn)托管技術(shù)使用冒泡就足夠了。
事件托管技術(shù)就是只要監(jiān)聽事件偵測(cè)事件是不是從目標(biāo)元素中發(fā)出的。里面會(huì)有一些跨瀏覽器的代碼,如果將它們移入一個(gè)可復(fù)用的庫(kù)里面,那么代碼就會(huì)變的很干凈。跨瀏覽器部分包括:
訪問(wèn)事件對(duì)象,并判斷事件緣(目標(biāo))。
結(jié)束文檔樹上冒泡。
阻止默認(rèn)動(dòng)作(可選)。
HTML:
最后,如果文章有什么錯(cuò)誤和疑問(wèn)的地方,請(qǐng)指出。與sf各位共勉!
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/85709.html
摘要:本文章記錄本人在深入學(xué)習(xí)中看書理解到的一些東西,加深記憶和并且整理記錄下來(lái),方便之后的復(fù)習(xí)。級(jí)年月,正式發(fā)布更新后的核心部分,并且在這次發(fā)布添加了一些新的規(guī)范,這次發(fā)布的稱為級(jí)規(guī)范。 本文章記錄本人在深入學(xué)習(xí)Javascirpt DOM中看書理解到的一些東西,加深記憶和并且整理記錄下來(lái),方便之后的復(fù)習(xí)。 DOM 版本 w3c 指定的DOM規(guī)范包括多個(gè)版本,不同的版本(或稱知為...
摘要:寫在前面目前專注深入學(xué)習(xí),特花了點(diǎn)時(shí)間整理了一些前端學(xué)習(xí)相關(guān)的書籍。大致分為以下大系列系列系列基礎(chǔ)系列應(yīng)用系列進(jìn)階系列類庫(kù)系列框架系列。這些書籍在這里免費(fèi)提供下載,有興趣的一起學(xué)習(xí)。 寫在前面 目前專注深入JavaScript學(xué)習(xí),特花了點(diǎn)時(shí)間整理了一些前端學(xué)習(xí)相關(guān)的書籍。 大致分為以下7大系列:CSS系列、DOM系列、JavaScript基礎(chǔ)系列、JavaScript應(yīng)用系列、Ja...
摘要:前言以深入學(xué)習(xí)技術(shù)棧為線索,記錄下學(xué)習(xí)的重要知識(shí)內(nèi)容。要傳入時(shí),必須使用屬性表達(dá)式。如果要使用自定義屬性,要使用前綴這與標(biāo)準(zhǔn)是一致的。 前言 以《深入學(xué)習(xí)react技術(shù)?!窞榫€索,記錄下學(xué)習(xí)React的重要知識(shí)內(nèi)容。本系列文章沒(méi)有涵蓋全部的react知識(shí)內(nèi)容,只是記錄下了學(xué)習(xí)之路上的重要知識(shí)點(diǎn),一方面是自己的總結(jié),同時(shí)拿出來(lái)和在學(xué)習(xí)react的人們一塊分享,共同進(jìn)步。 正文 一:rea...
摘要:前言接下來(lái)讓我們進(jìn)入新的章節(jié)漫談。正文一事件系統(tǒng)的事件系統(tǒng)事件系統(tǒng)符合標(biāo)準(zhǔn),不存在任何兼容性問(wèn)題,并且與原生的瀏覽器事件一樣有同樣的接口。所有的事件都自動(dòng)綁定到最外層。組織事件冒泡的行為只適用于合成系統(tǒng)中,且沒(méi)辦法阻止原生事件冒泡。 前言 接下來(lái)讓我們進(jìn)入新的章節(jié):漫談React。本篇文章主要講React事件系統(tǒng)和表單操作。 正文 一:事件系統(tǒng) 1.react的事件系統(tǒng)react事件系...
摘要:用于規(guī)范的類型與必需的狀態(tài)。表示由組件更改的數(shù)據(jù),通常是通過(guò)與用戶的交互來(lái)更改的。為了實(shí)現(xiàn)的修改,需要注冊(cè)事件處理程序到相應(yīng)的元素上。當(dāng)事件發(fā)生時(shí),將更新后的值是從中檢索,并通知組件。通常情況下,該函數(shù)初始化狀態(tài)使用,,或其他數(shù)據(jù)存儲(chǔ)。 前言 上一篇文章中,我們講到了JSX的一些用法和注意事項(xiàng),這次我們來(lái)講react中最基礎(chǔ)也是特別重要的內(nèi)容:組件。這篇文章包含組件的以下內(nèi)容:狀態(tài)、屬...
閱讀 3566·2021-11-22 13:53
閱讀 3609·2021-10-11 11:11
閱讀 1081·2019-08-30 14:12
閱讀 1390·2019-08-29 17:16
閱讀 823·2019-08-29 16:45
閱讀 3546·2019-08-29 12:56
閱讀 820·2019-08-28 17:55
閱讀 2227·2019-08-26 13:24