您好,登錄后才能下訂單哦!
小編給大家分享一下Dom節點怎么進行優化,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!
DOM操作對性能影響最大是因為它導致了瀏覽器的重繪和回流,我們都知道頁面UI的更改都是通過DOM操作實現的,DOM雖然提供了許多api方便我們操作dom,但DOM操作的代價很高,頁面前端代碼的性能瓶頸也大多集中在DOM操作上,所以前端性能優化的一個主要的關注點就是DOM操作的優化。
瀏覽器渲染機制:
瀏覽器渲染頁面
瀏覽器解析 HTML 文檔的源碼,然后構造出一個 DOM 樹,遇到樣式就異步計算。
異步計算好的樣式與dom樹合成,構建 render 樹。
進行布局(layout) render 樹。
進行繪制(painting) render 樹。
DOM樹與render樹的區別在于:樣式為display:none;的節點會在DOM樹中而不在渲染樹中。瀏覽器繪制了之后便開始解析js文件,根據js來確定是否重繪和重排。
頁面更改發生的操作:
回流:瀏覽器引擎發現render樹某個節點發生了變化影響了布局,需要倒回去重新渲染,我們稱這個回退的過程叫 回流。回流會從這個root frame開始遞歸往下,依次計算所有的結點幾何尺寸和位置。
重繪:改變某個元素的背景色、文字顏色、邊框顏色等等不影響頁面dom布局的操作。
js是單線程的,重繪和重排會阻塞用戶的操作以及影響網頁的性能
1、改變dom多個樣式,使用class,而非style,減少多次觸發回流重繪
舉例:改變dom元素寬高
var dom = document.getElementById('box') dom.style.width = '300px' dom.style.height = '300px'//訪問了三次dom,觸發了兩次回流和兩次重繪
優化后:
.change { width: 300px; height: 300px; } document.getElementById('p').className = 'change'//只觸發一次
2、列表類型批量修改,脫離文檔流再恢復,利用樣式為display:none;的節點會在DOM樹中而不在渲染樹中不會引起重繪回流。
如果要在一個dom集合中,給每個dom子節點加一個class,我們可以遍歷給每一個節點都加上class,這樣就觸發了多次的重繪和回流
/* //需要加入的樣式 .change { width: 300px; height: 300px; } */ var ul = document.getElementsByTagName('ul') var lis = document.getElementsByTagName('li') ul.style.display = 'none' for(var i = 0; i < lis.length; i++) { lis[i].className = 'change'; } ul.style.display = 'block'
3、DocumentFragment
虛擬DOM其實就是一個對象,js提供了reateDocumentFragment()方法用于創建一個空的虛擬節點對象,DocumentFragment節點不屬于文檔樹,當需要添加多個dom元素時,如果先將這些元素添加到DocumentFragment中,然后再將DocumentFragment對象添加到渲染樹上,會減少頁面渲染dom的次數,效率會明顯提升。
var frag = document.createDocumentFragment() //創建一個虛擬節點對象 for(var i = 0; i < 10; i++) { var li = document.createElement("li") li.innerHTML = '我是第' + i + 1 + '個元素' frag.appendChild(li) //將li元素加到虛擬節點對象上 } ul.appendChild(frag) //將虛擬節點對象加到ul上
其它
1、事件委托,利用瀏覽器事件,冒泡捕獲減少頁面事件綁定,我們可以指定一個事件處理程序就可以管理某一類型的所有事件。事件函數過多會占用大量內存,而且綁定事件的DOM元素越多會增加訪問dom的次數,對頁面的交互就緒時間也會有延遲。
// 事件委托前 var lis = document.getElementsByTagName('li') for(var i = 0; i < lis.length; i++) { lis[i].onclick = function() { console.log(this.innerHTML) }} // 利用瀏覽器事件通過父元素委托事件給子元素 var ul = document.getElementsByTagName('ul')ul.onclick = function(event) { //也可以做判斷給指定的子元素綁定事件 console.log(event.target.innerHTML)};
2、在循環中的優化減少操作dom次數
//例子1:減少在計算過程中操作dom // 優化前,訪問了好多次dom,這些都是細節問題,有經驗的繞過,小白平常多注意就行 for(var i = 0; i < 10; i++) { document.getElementById('el').innerHTML += '1'} // 優化后 var str = ''for(var i = 0; i < 10; i++) { str += '1'}document.getElementById('el').innerHTML = str/
這樣看獲取你體驗不到緩存節點長度的作用,請看下面的例子
//不緩存 var ps = document.getElementsByTagName("p"), i, p; for( i=0; i<ps.length; i++ ){ p = document.createElement("p"); document.body.appendChild("p"); }造成死循環,每次執行for循環都會動態獲取ps的長度,而我們每次進入循環都增加了一個DOM(p),ps的長度也+1. //緩存 var ps = document.getElementsByTagName("p"), i, p,len; for( i=0;len=ps.length;i<len; i++ ){ p = document.createElement("p"); document.body.appendChild("p"); }//使用變量保存ps的長度。
3、選擇器區別
獲取元素最常見的有兩種方法,getElementsByXXX()和queryselectorAll(),這兩種選擇器區別是很大的,前者是獲取動態集合,后者是獲取靜態集合
// 假設一開始有2個livar lis = document.getElementsByTagName('li') // 動態集合 var ul = document.getElementsByTagName('ul')[0] for(var i = 0; i < 3; i++) { console.log(lis.length) var newLi = document.createElement('li') ul.appendChild(newLi)}// 輸出結果:2, 3, 4 // 優化后 var lis = document.querySelectorAll('li') // 靜態集合 var ul = document.getElementsByTagName('ul')[0] for(var i = 0; i < 3; i++) { console.log(lis.length) var newLi = document.createElement('li') ul.appendChild(newLi)}// 輸出結果:2, 2, 2
對靜態集合的操作不會引起對文檔的重新查詢,相比于動態集合更加優化。
以上是“Dom節點怎么進行優化”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。