首先澄清两个概念——Repaint 和 Reflow:Repaint 也叫 Redraw,它指的是一种不会影响当前 DOM 的结构和布局的一种重绘动作。如下动作会产生 Repaint 动作:
不可见到可见(visibility 样式属性);颜色或图片变化(background, border-color, color 样式属性);不改变页面元素大小,形状和位置,但改变其外观的变化Reflow 比起 Repaint 来讲就是一种更加显著的变化了。它主要发生在 DOM 树被操作的时候,任何改变 DOM 的结构和布局都会产生 Reflow。但一个元素的 Reflow 操作发生时,它的所有父元素和子元素都会放生 Reflow,最后 Reflow 必然会导致 Repaint 的产生。举例说明,如下动作会产生 Reflow 动作:
浏览器窗口的变化;DOM 节点的添加删除操作一些改变页面元素大小,形状和位置的操作的触发通过 Reflow 和 Repaint 的介绍可知,每次 Reflow 比其 Repaint 会带来更多的资源消耗,因此,我们应该尽量减少 Reflow 的发生,或者将其转化为只会触发 Repaint 操作的代码。
var tipBox = document.createElement('div'); document.body.appendChild('tipBox');//reflow var tip1 = document.createElement('div'); var tip2 = document.createElement('div'); tipBox.appendChild(tip1);//reflow tipBox.appendChild(tip2);//reflow如上的代码,会产生三次reflow,优化后的代码如下:
var tipBox = document.createElement('div'); tip1 = document.createElement('div'); tip2 = document.createElement('div'); tipBox.appendChild(tip1); tipBox.appendChild(tip2); document.body.appendChild('tipBox');//reflow当然还可以利用 display 来减少reflow次数
var tipBox = document.getElementById('tipBox'); tipBox.style.display = 'none';//reflow tipBox.appendChild(tip1); tipBox.appendChild(tip2); tipBox.appendChild(tip3); tipBox.appendChild(tip4); tipBox.appendChild(tip5); tipBox.style.width = 120; tipBox.style.height = 60; tipBox.style.display = 'block';//reflowDOM元素测量属性和方法也会触发reflow,如下:
var tipWidth = tipBox.offsetWidth;//reflow tipScrollLeft = tipBox.scrollLeft;//reflow display = window.getComputedStyle(div,'').getPropertyValue('display');//reflow触发reflow的属性和方法大概有这些:
offsetLeftoffsetTopoffsetHeightoffsetWidthscrollTop/Left/Width/HeightclientTop/Left/Width/HeightgetComputedStyle()currentStyle(in IE))我们可以用临时变量将“offsetWidth”的值缓存起来,这样就不用每次访问“offsetWidth”属性。这种方式在循环里面非常适用,可以极大地提高性能。
如果有批量的样式属性需要修改,建议通过替换className的方式来降低reflow的次数,曾经有这样一个场景:有三个intput,分别对 应下面三个图片和三个内容区域,第二input选中的时候,第二图片显示,其他图片隐藏,第二块内容显示,其他内容隐藏,直接操作DOM节点的代码如下
var input = []; pics = []; contents = []; ...... for(var i = 0;i<3;i++){ input[i].onclick = function(e){ show(pics,i);//reflow两次 show(contents,i);//reflow两次 } } function show(target,j){ for(var i = 0,i<3;i++){ target[i].style.display = 'none';//reflow } target[j].style.display = 'block';//reflow }如果是通过css预先定义元素的隐藏和显示,通过对父级的className进行操纵,将会把reflow的次数减少到1次
.pbox .pic,.pbox content{display:none} .J_pbox_0 .pic0,.J_pbox_0 .content0{diplay:block} .J_pbox_1 .pic1,.J_pbox_1 .content1{diplay:block} .J_pbox_2 .pic2,.J_pbox_2 .content2{diplay:block} var input = [], parentBox = document.getELementById('J_Pbox'); ...... for(var i = 0;i<3;i++){ input[i].onclick = function(e){ parentBox.className = 'pbox J_pbox_'+i;//reflow一次 } }
转载自:http://ued.alimama.com/front-end/quick-tips-among-yahoo-n-rules/