重排与重绘
当DOM的变化引起了元素的几何属性发生变化,浏览器不得不重新计算元素的几何属性,并重新构建渲染树,这个过程称为重排。注意这里至少会有一次重排-初始化页面布局。
由于节点的几何属性发生改变或者由于样式发生改变,例如改变元素背景色时,屏幕上的部分内容需要更新。这样的更新被称为重绘。
由于浏览器渲染界面是基于流式布局模型的,也就是某一个DOM节点信息更改了,就需要对DOM结构重新进行计算,重新布局界面在,再次引发重排。
引起重排的操作有:
(1)页面首次渲染
(2)浏览器窗口大小发生变化(resize事件发生时)
(3)元素尺寸(大小,外边距,边框)或位置发生改变,或使用动画
(4)元素内容变化
(5)元素字体大小变化
(6)添加或删除可见的DOM元素
(7)设置style属性
(8)读取某些元素属性(offsetLeft/Top/Height/Width)
重排一定会引起重绘,但是重绘不一定会引起重排。
当DOM结构发生变化时,例如节点的增减、移动等,也会触发重排。浏览器引擎布局的过程,类似于树的先序遍历,是一个从上到下从左到右的过程。通常在这个过程中,当前元素不会再影响其前面已经遍历过的元素,所以,如果在body最前面插入一个元素,会导致整个文档的重新渲染;而在其后插入一个元素,则不会影响到前面的元素。
如何减少重排次数?
(1)避免设置大量的style属性,因为通过设置style属性改变节点样式的话,每一次设置都会触发一次reflow,所以最好是使用class属性
(2)将需要多次重排的元素,position属性设置为absolute或fixed,这样元素就会脱离文档流,它的变化不会影响到其他元素。例如有动画效果的元素最好设置为绝对定位。
(3)由于display属性为none的元素不在渲染树中,对隐藏的元素操作不会引发其他元素的重排。如果对一个元素进行复杂的操作时,可以先隐藏他,操作完成之后再显示。这样只在隐藏和显示时触发两次重排,但是这可能导致浏览器的闪烁。
这个会在显示与隐藏节点的时候,产生两次重绘。
function appendDataToElement(appendToElement,data){ let li; for(let i=0;i<data.length;i++){ li=document.createElement('li'); li.textContent='text'; appendToElement.appendChild(li); } } const ul=document.getElementById('list'); ul.style.display='none'; appendDataToElement(ul,data); ul.style.display='block';
(4)不要把DOM节点的属性值放在循环里当成循环里的变量,例如改变DOM的内容,先定义一个变量,最后再添加到DOM上。
var position=document.getElementById('position'); var jobHTML=''; for(var i=0;i<jobArr.length;i++){ jobHTML+='<option value='+i+'>'+jobArr[i]+'</option>'; } position.innerHTML+=jobHTML;
(5)使用文档片段在当前DOM之外构建一颗子树,再把它拷贝回文档
const ul = document.getElementById('list'); const fragment = document.createDocumentFragment(); appendDataToElement(fragment, data); ul.appendChild(fragment);