【JavaScript】迴流(reflow)與重繪(repaint)

重繪與迴流

首先要了解頁面是如何呈現的javascript

  1. HTML文檔加載後生成DOM樹(包括display:none;元素);
  2. 在DOM樹的基礎上配合css樣式結構體生成render樹(不包含display:none;、head節點,包含visibility:hidden;節點),即頁面中的佔位肯定了.
  3. 最後繪製頁面(也叫渲染),不會改變頁面佈局的一些屬性:color、背景色等。
  • 重繪(repaint):更新頁面元素的屬性引發的,如顏色、透明度等不會改變頁面佈局而須要從新渲染的。
  • 迴流(reflow):render樹中部分或所有元素的尺寸、佈局、隱藏等(內容、結構、位置)改變引發的,每一個頁面至少有一次迴流(即初始構建頁面時),成本較高。
  • DOM操做(對元素的增刪改、順序變化等)
  • 內容變化,包括表單區域內的文本變化
  • css屬性的更改或者從新計算
  • 增刪樣式表內容
  • 修改class屬性
  • 瀏覽器窗口變化(滾動或縮放)
  • 僞類樣式激活(:hover等)

這些狀況會引發迴流,減小回流就是儘可能避免或減小這寫操做的執行次數。css

減小頁面重繪與迴流:
頁面中須要須要動態生成id爲box的div中的內容,結果以下:java

<div id="box"> <p class="btn-title"><i class="iconfont"></i>項目階段</p> <ul class="btn-group" id="proStepul"> <li class="btn-item" data_id="">所有</li> <li class="btn-item" data_id="">所有</li> <li class="btn-item" data_id="">所有</li> <li class="btn-item" data_id="">所有</li> <li class="btn-item" data_id="">所有</li> </ul> </div>

通常的作法能夠用innerHTML或者createElement:django

var Obox = document.getElementById("box"); Obox.innerHTML = '<p class="btn-title"><i class="iconfont"></i>項目階段</p>'; Obox.innerHTML += '<ul class="btn-group" id="proStepul">'; for(var i=0;i<5;i++){ Obox.innerHTML += '<li class="btn-item" data_id="">所有</li>'; } Obox.innerHTML +='</ul>';

這樣寫要向Obox中寫入不少次。成本增高,建議的方法是用變量存儲而後一次寫入。瀏覽器

var Obox = document.getElementById("box"); var str = ''; str = '<p class="btn-title"><i class="iconfont"></i>項目階段</p>'; str += '<ul class="btn-group" id="proStepul">'; for(var i=0;i<5;i++){ str += '<li class="btn-item" data_id="">所有</li>'; } str +='</ul>'; Obox.innerHTML = str;

用createElement方法以下:但是這樣的結構很糟糕,屢次寫入,增長不少重繪與迴流。app

var Obox = document.getElementById("box"); var Op = document.createElement("p"); Obox.appendChild(Op); Op.setAttribute("class","btn-title"); Op.innerHTML ="項目階段"; var Oi = document.createElement("i"); Op.appendChild(Oi); Oi.setAttribute("class","iconfont"); var Oul = document.createElement("ul"); Obox.appendChild(Oul); Oul.setAttribute("class","btn-group"); Oul.setAttribute("id","proStepul"); for(var i=0;i<5;i++){ var Oli = document.createElement("li"); Oul.appendChild(Oli); Oli.setAttribute("class","btn-item"); }

合理的方法是:先構建元素,而後設置元素的屬性等,最後再將元素添加到頁面相應位置:佈局

var Obox = document.getElementById("box"); var Op = document.createElement("p"); //Obox.appendChild(Op); Op.setAttribute("class","btn-title"); Op.innerHTML ="項目階段"; var Oi = document.createElement("i"); Op.appendChild(Oi); Oi.setAttribute("class","iconfont"); var Oul = document.createElement("ul"); //Obox.appendChild(Oul); Oul.setAttribute("class","btn-group"); Oul.setAttribute("id","proStepul"); for(var i=0;i<5;i++){ var Oli = document.createElement("li"); Oul.appendChild(Oli); Oli.setAttribute("class","btn-item"); } Obox.appendChild(Op); Obox.appendChild(Oul);

這裏只需將新建元素寫入頁面的操做移到最後便可,至於元素在未寫入頁面以前的操做順序如何,對頁面並無什麼影響,不會形成頁面迴流或者重繪。
有一種狀況爲:須要像頁面中寫入多個同一級的元素,以下:向ul元素中寫入多個li元素ui

<ul class="btn-group on" id="proStepul"> <li class="btn-item on" >所有</li> <li class="btn-item on" >所有</li> <li class="btn-item on" >所有</li> <li class="btn-item on" >所有</li> <li class="btn-item on" >所有</li> </ul>

若是用以前的方法,不可避免的要寫五個Oul.appendChild("Oul");了,這時咱們能夠用JS提供的能夠整合多個碎片的中介----document.createDocumentFragment();spa

var Oul = document.getElementById("proStepul"); var obj = document.createDocumentFragment(); for (var i = 0; i < 5; i++) { var Oli = document.createElement("li"); Oli.setAttribute("class", "btn-item"); obj.appendChild(Oli); } Oul.appendChild(obj);
相關文章
相關標籤/搜索