1.document.write和innerHtml
document.write // 重排整个页面
innerHtml //重绘页面的某些部分
2.DOM树和渲染树
DOM树:表示页面结构
渲染树:表示DOM节点如何显示
3.重排和重绘
重排:当DOM元素影响了元素的**几何属性**(例如宽和高),浏览器需要重新计算元素的几何属性,
同样其它元素的几何属性也会和位置也会因此受到影响。浏览器会使渲染树中受到影响的
部分失效,并重新构造渲染树。
重绘:完成重排后,浏览器会重新绘制受影响的部分到屏幕上中。
重排发生的情况:
- 页面渲染器初始化。
- 添加或删除可见的DOM元素。
- 元素位置改变。
- 元素的尺寸改变(包括:内外边距、边框厚度、宽度、高度等属性的改变)。
- 内容改变。
- 浏览器窗口尺寸改变。
- 读取某些元素属性:(offsetLeft/Top/Height/Width, clientTop/Left/Width/Height, scrollTop/Left/Width/Height, width/height, getComputedStyle(), currentStyle(IE))
触发重排的属性
有些节点,当你改变他时,会需要重新布局(这也意味着需要重新计算其他被影响的节点的位置和大小)
这种情况下,被影响的DOM树越大(可见节点),重绘所需要的时间就会越长,所以需要尽力避免这些属
性。
一些常用的改变时会触发重布局的属性:
盒子模型相关属性会触发重布局:
- width
- height
- padding
- margin
- display
- border-width
- border
- min-height
定位属性及浮动也会触发重布局:
- top
- bottom
- left
- right
- position
- float
- clear
改变节点内部文字结构也会触发重布局:
- text-align
- overflow-y
- font-weight
- overflow
- font-family
- line-height
- vertival-align
- white-space
- font-size
重绘发生的情况
重绘发生在元素的可见的外观被改变,但并没有影响到布局的时候。比如,仅修改DOM元素的
字体颜色(只有Repaint,因为不需要调整布局)
触发重绘的属性
修改时只触发重绘的属性有:
- color
- border-style
- border-radius
- visibility
- text-decoration
- background
- background-image
- background-position
- background-repeat
- background-size
- outline-color
- outline
- outline-style
- outline-width
- box-shadow
注意:重排一定会引起重绘,但重绘不一定会引起重排。重排和重绘都会影响浏览器性能。
优化
1.改变元素的className
例如:
// css
.active {
padding: 5px;
border-left: 1px;
border-right: 2px;
}
// javascript
var el = document.querySelector('.el');
el.className = 'active';
2.需要批量创建或修改多个DOM节点时:
1)隐藏元素,进行修改后,然后再显示该元素
例如:
let ul = document.querySelector('#mylist');
ul.style.display = 'none';
appendNode(ul, data);
ul.style.display = 'block';
先将ul设置为display:none;然后进行页面布局等操作;设置完成后将元素设置为
display:block;这样的话就只引发两次重绘和重排,分别是控制元素的显示与隐藏。
2)使用文档片段创建一个子树,然后再拷贝到文档中
例如:
let fragment = document.createDocumentFragment();
appendNode(fragment, data);
ul.appendChild(fragment);
文档片段是一个轻量级的document对象,它设计的目的就是用于更新,移动节点之类的任务,
而且文档片段还有一个好处就是,当向一个节点添加文档片段时,添加的是文档片段的子节点群,
自身不会被添加进去,这样只会触发一次重排。
3)将原始元素拷贝到一个独立的节点中,操作这个节点,然后覆盖原始元素
例如:
let old = document.querySelector('#mylist');
let clone = old.cloneNode(true);
appendNode(clone, data);
old.parentNode.replaceChild(clone, old);
这种方法也是只有一次重排
3.缓存布局信息
4.将需要多次重排的元素,position属性设为absolute或fixed,元素脱离了文档流,
它的变化不会影响到其他元素;
5.尽量不要使用table布局。