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