【javascript基础】Repaint 和 Reflow
2012-12-24 17:08 sniper007 阅读(344) 评论(0) 编辑 收藏 举报Repaint又叫Redraw,重绘,它是指一种不影响当前dom结构的和布局的一种重绘动作。
以下的动作都会促发Repaint:
- 不可见或可见(visibility);
- 颜色和图片改变(background,border-color,color之类的属性);
- 不改变页面元素大小,形状和位置,但改变其外观的变化。
Reflow,又叫重构, 比起 Repaint 来讲就是一种更加显著的变化了。它主要发生在 DOM 树被操作的时候,任何改变 DOM 的结构和布局都会产生 Reflow。但一个元素的 Reflow 操作发生时,它的所有父元素和子元素都会发生 Reflow,最后 Reflow 必然会导致 Repaint 的产生。举例说明,如下动作会产生 Repaint 动作:
- 浏览器窗口的变化;
- DOM 节点的添加删除操作;
- 一些改变页面元素大小,形状和位置的操作的触发。
通过 Reflow 和 Repaint 的介绍可知,每次 Reflow 比其 Repaint 会带来更多的资源消耗,我们应该尽量减少 Reflow 的发生,或者将其转化为只会触发 Repaint 操作的代码。
参考如下代码:
var pDiv = document.createElement(“div”); document.body.appendChild(pDiv);----- reflow var cDiv1 = document.createElement(“div”); var cDiv2 = document.createElement(“div”); pDiv.appendChild(cDiv1);----- reflow pDiv.appendChild(cDiv2);----- reflow
这是我们经常接触的代码了,但是这段代码会产生 3 次 reflow。再看如下代码:
var pDiv = document.createElement(“div”); var cDiv1 = document.createElement(“div”); var cDiv2 = document.createElement(“div”); pDiv.appendChild(cDiv1); pDiv.appendChild(cDiv2); document.body.appendChild(pDiv);----- reflow
这里便只有一次 reflow,所以我们推荐这种 DOM 节点操作的方式。
关于上述较少 Reflow 操作的解决方案,还有一种可以参考的模式:
var pDiv = document.getElementById(“parent”); pDiv.style.display = “none”----- reflow pDiv.appendChild(cDiv1); pDiv.appendChild(cDiv2); pDiv.appendChild(cDiv3); pDiv.appendChild(cDiv4); pDiv.appendChild(cDiv5); pDiv.style.width = “100px”; pDiv.style.height = “100px”; pDiv.style.display = “block”----- reflow
先隐藏 pDiv,再显示,这样,隐藏和显示之间的操作便不会产生任何的 Reflow,提高了效率。
DOM 元素里面有一些特殊的测量属性的访问和方法的调用,也会触发 Reflow,比较典型的就是“offsetWidth”属性和“getComputedStyle”方法。
这些测量属性和方法大致有这些:
- offsetLeft
- offsetTop
- offsetHeight
- offsetWidth
- scrollTop/Left/Width/Height
- clientTop/Left/Width/Height
- getComputedStyle()
- currentStyle(in IE))
这些属性和方法的访问和调用,都会触发 Reflow 的产生,我们应该尽量减少对这些属性和方法的访问和调用,参考如下代码:
var pe = document.getElementById(“pos_element”); var result = document.getElementById(“result_element”); var pOffsetWidth = pe.offsetWidth; result.children[0].style.width = pOffsetWidth; result.children[1].style.width = pOffsetWidth; result.children[2].style.width = pOffsetWidth; …………其他修改………… |
这里我们可以用临时变量将“offsetWidth”的值缓存起来,这样就不用每次访问“offsetWidth”属性。这种方式在循环里面非常适用,可以极大地提高性能。
我们肯定经常见到如下的代码:
var sElement = document.getElementById(“pos_element”); sElement.style.border = ‘ 1px solid red ’ sElement.style.backgroundColor = ‘ silver ’ sElement.style.padding = ‘ 2px 3px ’ sElement.style.marginLeft = ‘ 5px ’ |
但是可以看到,这里的每一个样式的改变,都会产生 Reflow。需要减少这种情况的发生,我们可以这样做:
解决方案 1:
.class1 { border: ‘ 1px solid red ’ background-color: ‘ silver ’ padding: ‘ 2px 3px ’ margin-left: ‘ 5px ’ } document.getElementById(“pos_element”).className = ‘class1’ ; |
用 class 替代 style,可以将原有的所有 Reflow 或 Repaint 的次数都缩减到一个。
解决方案 2:
var sElement = document.getElementById(“pos_element”); var newStyle = ‘ border: 1px solid red; ’ + ‘ background-color: silver; ’ + ‘ padding: 2px 3px; ’ + “margin-left: 5px;” sElement.style.cssText += newStyle; |
一次性设置所有样式,也是减少 Reflow 提高性能的方法。