首頁 >web前端 >js教程 >Dom節點如何進行優化

Dom節點如何進行優化

醉折花枝作酒筹
醉折花枝作酒筹原創
2021-04-12 11:16:392485瀏覽

本文為大家介紹Dom節點進行最佳化的方案。有一定的參考價值,有需要的朋友可以參考一下,希望對大家有幫助。

Dom節點如何進行優化

DOM操作對效能影響最大是因為它導致了瀏覽器的重繪和回流,我們都知道頁面UI的變更都是透過DOM操作實現的,DOM雖然提供了許多api方便我們操作dom,但DOM操作的代價很高,頁面前端程式碼的效能瓶頸也大多集中在DOM操作上,所以前端效能最佳化的一個主要的重點就是DOM操作的最佳化。

瀏覽器渲染機制:

Dom節點如何進行優化
瀏覽器渲染頁面
Dom節點如何進行優化

  1. 瀏覽器解析HTML 文檔的來源碼,然後建構出一個DOM 樹,遇到樣式就非同步計算。

  2. 非同步計算好的樣式與dom樹合成,建構 render 樹。

  3. 進行佈局(layout) render 樹。

  4. 進行繪製(painting) render 樹。

DOM樹與render樹的差別在於:樣式為display:none;的節點會在DOM樹而不在渲染樹。瀏覽器繪製了之後便開始解析js文件,根據js確定是否重繪和重排。

回流·重繪

頁面變更發生的動作:

  1. 回流:瀏覽器引擎發現render樹某個節點發生了變化影響了佈局,需要倒回去重新渲染,我們稱這個回退的過程叫回流。回流會從這個root frame開始遞歸往下,依序計算所有的結點幾何尺寸和位置。
  2. 重繪:改變某個元素的背景色、文字顏色、邊框顏色等等不影響頁面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,我們可以遍歷給每個節點加上cla​​ss,這樣就觸發了多次的重繪和回流

/* //需要加入的样式
.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 = &#39;change&#39;;
     }
     ul.style.display = &#39;block&#39;

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 = &#39;我是第&#39; + i + 1 + &#39;个元素&#39;		
    frag.appendChild(li)  //将li元素加到虚拟节点对象上
    } 			
    ul.appendChild(frag)  //将虚拟节点对象加到ul上

其它

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

// 事件委托前
var lis = document.getElementsByTagName(&#39;li&#39;)
for(var i = 0; i < lis.length; i++) {
   lis[i].onclick = function() {
      console.log(this.innerHTML)
   }}    // 利用浏览器事件通过父元素委托事件给子元素
   var ul = document.getElementsByTagName(&#39;ul&#39;)ul.onclick = function(event) {
	//也可以做判断给指定的子元素绑定事件
   console.log(event.target.innerHTML)};

2、在循環中的優化減少操作dom次數

//例子1:减少在计算过程中操作dom
// 优化前,访问了好多次dom,这些都是细节问题,有经验的绕过,小白平常多注意就行
for(var i = 0; i < 10; i++) {
    document.getElementById(&#39;el&#39;).innerHTML += &#39;1&#39;} 
    // 优化后 
    var str = &#39;&#39;for(var i = 0; i < 10; i++) {
    str += &#39;1&#39;}document.getElementById(&#39;el&#39;).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(&#39;li&#39;)  // 动态集合
var ul = document.getElementsByTagName(&#39;ul&#39;)[0]
 for(var i = 0; i < 3; i++) {
    console.log(lis.length)
    var newLi = document.createElement(&#39;li&#39;)
    ul.appendChild(newLi)}// 输出结果:2, 3, 4
    // 优化后
    var lis = document.querySelectorAll(&#39;li&#39;)  // 静态集合 
    var ul = document.getElementsByTagName(&#39;ul&#39;)[0]
 for(var i = 0; i < 3; i++) {
    console.log(lis.length)
    var newLi = document.createElement(&#39;li&#39;)
    ul.appendChild(newLi)}// 输出结果:2, 2, 2

對靜態集合的操作不會造成對文件的重新查詢,相較於動態集合更加最佳化。

推薦學習:javascript影片教學

#

以上是Dom節點如何進行優化的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn