【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);
相关文章
相关标签/搜索