溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Dom節(jié)點(diǎn)怎么進(jìn)行優(yōu)化

發(fā)布時(shí)間:2021-04-12 13:05:44 來源:億速云 閱讀:115 作者:小新 欄目:web開發(fā)

小編給大家分享一下Dom節(jié)點(diǎn)怎么進(jìn)行優(yōu)化,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!

DOM操作對(duì)性能影響最大是因?yàn)樗鼘?dǎo)致了瀏覽器的重繪和回流,我們都知道頁面UI的更改都是通過DOM操作實(shí)現(xiàn)的,DOM雖然提供了許多api方便我們操作dom,但DOM操作的代價(jià)很高,頁面前端代碼的性能瓶頸也大多集中在DOM操作上,所以前端性能優(yōu)化的一個(gè)主要的關(guān)注點(diǎn)就是DOM操作的優(yōu)化。

瀏覽器渲染機(jī)制:

Dom節(jié)點(diǎn)怎么進(jìn)行優(yōu)化
瀏覽器渲染頁面
Dom節(jié)點(diǎn)怎么進(jìn)行優(yōu)化

  1. 瀏覽器解析 HTML 文檔的源碼,然后構(gòu)造出一個(gè) DOM 樹,遇到樣式就異步計(jì)算。

  2. 異步計(jì)算好的樣式與dom樹合成,構(gòu)建 render 樹。

  3. 進(jìn)行布局(layout) render 樹。

  4. 進(jìn)行繪制(painting) render 樹。

DOM樹與render樹的區(qū)別在于:樣式為display:none;的節(jié)點(diǎn)會(huì)在DOM樹中而不在渲染樹中。瀏覽器繪制了之后便開始解析js文件,根據(jù)js來確定是否重繪和重排。

回流·重繪

頁面更改發(fā)生的操作:

  1. 回流:瀏覽器引擎發(fā)現(xiàn)render樹某個(gè)節(jié)點(diǎn)發(fā)生了變化影響了布局,需要倒回去重新渲染,我們稱這個(gè)回退的過程叫 回流。回流會(huì)從這個(gè)root frame開始遞歸往下,依次計(jì)算所有的結(jié)點(diǎn)幾何尺寸和位置。

  2. 重繪:改變某個(gè)元素的背景色、文字顏色、邊框顏色等等不影響頁面dom布局的操作。

js是單線程的,重繪和重排會(huì)阻塞用戶的操作以及影響網(wǎng)頁的性能

優(yōu)化:減少回流重繪次數(shù)

1、改變dom多個(gè)樣式,使用class,而非style,減少多次觸發(fā)回流重繪
舉例:改變dom元素寬高

var dom = document.getElementById('box')
dom.style.width = '300px'
dom.style.height = '300px'//訪問了三次dom,觸發(fā)了兩次回流和兩次重繪

優(yōu)化后:

.change {
    width: 300px;
    height: 300px;
    }
    document.getElementById('p').className = 'change'//只觸發(fā)一次

2、列表類型批量修改,脫離文檔流再恢復(fù),利用樣式為display:none;的節(jié)點(diǎn)會(huì)在DOM樹中而不在渲染樹中不會(huì)引起重繪回流。

如果要在一個(gè)dom集合中,給每個(gè)dom子節(jié)點(diǎn)加一個(gè)class,我們可以遍歷給每一個(gè)節(jié)點(diǎn)都加上class,這樣就觸發(fā)了多次的重繪和回流

/* //需要加入的樣式
.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其實(shí)就是一個(gè)對(duì)象,js提供了reateDocumentFragment()方法用于創(chuàng)建一個(gè)空的虛擬節(jié)點(diǎn)對(duì)象,DocumentFragment節(jié)點(diǎn)不屬于文檔樹,當(dāng)需要添加多個(gè)dom元素時(shí),如果先將這些元素添加到DocumentFragment中,然后再將DocumentFragment對(duì)象添加到渲染樹上,會(huì)減少頁面渲染dom的次數(shù),效率會(huì)明顯提升。

var frag = document.createDocumentFragment() //創(chuàng)建一個(gè)虛擬節(jié)點(diǎn)對(duì)象	
for(var i = 0; i < 10; i++) {				
    var li = document.createElement("li")		
    li.innerHTML = '我是第' + i + 1 + '個(gè)元素'		
    frag.appendChild(li)  //將li元素加到虛擬節(jié)點(diǎn)對(duì)象上
    } 			
    ul.appendChild(frag)  //將虛擬節(jié)點(diǎn)對(duì)象加到ul上

其它

1、事件委托,利用瀏覽器事件,冒泡捕獲減少頁面事件綁定,我們可以指定一個(gè)事件處理程序就可以管理某一類型的所有事件。事件函數(shù)過多會(huì)占用大量內(nèi)存,而且綁定事件的DOM元素越多會(huì)增加訪問dom的次數(shù),對(duì)頁面的交互就緒時(shí)間也會(huì)有延遲。

// 事件委托前
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、在循環(huán)中的優(yōu)化減少操作dom次數(shù)

//例子1:減少在計(jì)算過程中操作dom
// 優(yōu)化前,訪問了好多次dom,這些都是細(xì)節(jié)問題,有經(jīng)驗(yàn)的繞過,小白平常多注意就行
for(var i = 0; i < 10; i++) {
    document.getElementById('el').innerHTML += '1'} 
    // 優(yōu)化后 
    var str = ''for(var i = 0; i < 10; i++) {
    str += '1'}document.getElementById('el').innerHTML = str/

這樣看獲取你體驗(yàn)不到緩存節(jié)點(diǎn)長度的作用,請(qǐng)看下面的例子

//不緩存
var ps = document.getElementsByTagName("p"), i, p;
for( i=0; i<ps.length; i++ ){  
    p = document.createElement("p");
    document.body.appendChild("p");
    }造成死循環(huán),每次執(zhí)行for循環(huán)都會(huì)動(dòng)態(tài)獲取ps的長度,而我們每次進(jìn)入循環(huán)都增加了一個(gè)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、選擇器區(qū)別

獲取元素最常見的有兩種方法,getElementsByXXX()和queryselectorAll(),這兩種選擇器區(qū)別是很大的,前者是獲取動(dòng)態(tài)集合,后者是獲取靜態(tài)集合

// 假設(shè)一開始有2個(gè)livar 
lis = document.getElementsByTagName('li')  // 動(dòng)態(tài)集合
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)}// 輸出結(jié)果:2, 3, 4
    // 優(yōu)化后
    var lis = document.querySelectorAll('li')  // 靜態(tài)集合 
    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)}// 輸出結(jié)果:2, 2, 2

對(duì)靜態(tài)集合的操作不會(huì)引起對(duì)文檔的重新查詢,相比于動(dòng)態(tài)集合更加優(yōu)化。

以上是“Dom節(jié)點(diǎn)怎么進(jìn)行優(yōu)化”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對(duì)大家有所幫助,如果還想學(xué)習(xí)更多知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

dom
AI