一聚教程网:一个值得你收藏的教程网站

最新下载

热门教程

javascript dom 操作优化

时间:2011-11-29 编辑:简简单单 来源:一聚教程网

DOM 操作优化
首先澄清两个概念——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';//reflow

DOM元素测量属性和方法也会触发reflow,如下:

 代码如下 复制代码
var tipWidth = tipBox.offsetWidth;//reflow
   tipScrollLeft = tipBox.scrollLeft;//reflow
   display = window.getComputedStyle(div,'').getPropertyValue('display');//reflow

触发reflow的属性和方法大概有这些:

 代码如下 复制代码
offsetLeft
offsetTop
offsetHeight
offsetWidth
scrollTop/Left/Width/Height
clientTop/Left/Width/Height
getComputedStyle()
currentStyle(in IE))

我们可以用临时变量将“offsetWidth”的值缓存起来,这样就不用每次访问“offsetWidth”属性。这种方式在循环里面非常适用,可以极大地提高性能。
如果有批量的样式属性需要修改,建议通过替换className的方式来降低reflow的次数,曾经有这样一个场景:有三个intput,分别对应下面三个图片和三个内容区域,第二input选中的时候,第二图片显示,其他图片隐藏,第二块内容显示,其他内容隐藏,直接操作DOM节点的代码如下

 代码如下 复制代码

var input = [];
   pics = [];
   contents = [];
......
inputFrame.onclick =function(e){
    var _e,_target;
    _e = e ? window.event : null;
    if(!_e){
      return;
   }else{
     _target = _e.srcElement || _e.target ;
     _index = getIndex(_target);//reflow两次
    show(_target,_index);//reflow两次
   }

}
function show(target,j){
 for(var i = 0,i<3;i++){
  target[i].style.display = 'none';//reflow
 }
 target[j].style.display = 'block';//reflow
}
function getIndex(targer){
    if(target){
    .....//获取当前的元素索引
    return index;
    }
}


如果是通过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');
......
inputFrame.onclick =function(e){
    var _e,_target;
    if(){
     ...
    }else{
     ...
      parentBox.className = 'pbox J_pbox_'+_infex;//reflow一次
    }
}

热门栏目