DOM编程
1.文档对象模型(DOM)
访问的dom越多,代码的执行速度就越慢。
2.innerHtml和DOM方法
更改dom的时候,使用innerHTML(字符串拼接)和dom方法(
document.createElement();document.createTextNode();
);旧版本的浏览器如,IE6等innerHTML速度更快,反而新版的浏览器dom方法更快。总的来说,随着技术发展差异不大,具体使用哪种方法,还是与你个人的代码风格有关。
3.节点克隆
使用
ele.cloneNode()
克隆节点更有效率,但是提高的不多。
4.集合
遍历数组比遍历集合更快;如果需要遍历一个集合看业务是否需要将集合转换成数组;
function toArray(coll) {
for(var i=0,a=[],len=coll.length;i<len;i++){
a[i]=coll[i];
}
return a;
}
当
var coll=document.getElementsByTagName("div");这时候的length,每次访问都会导致集合更新,会在所有的浏览器上产生明显的性能损失。所以,将length放入到一个变量中
len`。这样效率会更高。
一般来说对于,任何类型的dom访问,如果同一个dom属性或方法被访问一次以上,最好使用一个局部变量缓存此dom成员,当遍历一个集合时,第一个优化是将集合引用存储于局部变量,并在循环之外缓存length。然后,如果在循环中多次访问同一个集合元素,那么使用局部变量缓存他。见下面的代码
//slow
function collectin() {
var coll = document.getElementsByTagName("div"),
len = coll.length,
name = "";
for (var con = 0; con < len; con++) {
name = document.getElementsByName("div")[con].nodeName;
name = document.getElementsByName("div")[con].nodeType;
name = document.getElementsByName("div")[con].tagName;
}
return name;
}
//faster
function collectin() {
var coll = document.getElementsByTagName("div"),
len = coll.length,
name = "",
ele = null;
for (var con = 0; con < len; con++) {
ele=coll[con];
name = ele.nodeName;
name = ele.nodeType;
name = ele.tagName;
}
return name;
}
遍历children
比childNodes
更快。如果浏览器支持 document.querySelectorAll()
,那么最好使用它。
document.querySelectorAll("div.warning div.notice")
dom重新排版和重绘代价昂贵,所以,提高程序响应速度好的方法是减少此类的操作,应该讲多个dom和风格改变合并到一个批次中一次性执行。
var computed=document.defaultView.getComputedStyle(document.body,"");
修改css样式,可以使用更改css的类名的方法,而不修改内联样式,或者使用cssText
;
ele.style.cssText="background-color: #f00;border: 1px solid #0f0;";
避免一个一个的修改元素的style,如:ele.style.padding="5px"
5.批量修改dom(渲染页面)
尽量最小数量的dom操作和重排版。在文档外创建一个文档片段,然后在把他添加到dom中;只引发一次排版,只触发一次“存在的dom”;
var frag=document.createDocumentFragment();
frag.appendChild(document.createElement("li"));
document.querySelector("#wrap").appendChild(frag);
createDocumentFragment的介绍
在一些简单的动画的时候,设置局部变量远比直接使用要优化的多;
6.将元素提出动画流
1.页面顶部可以“折叠/展开”的元素称为动画元素,用绝对坐标对它进行绝对定位,当他尺寸改变时,就不会推动页面其他元素的位置,而只是覆盖其他元素。
2.展开动作只在“动画元素”中进行,这时候其他元素的坐标并没发生改变,换句话说,其他元素并没有因为“动画元素”的扩大而随之下移,而是任由动画元素覆盖。
3.“动画元素”的动画结束时,将其他元素的动画移动到动画元素的下方,即元素重新定位,页面“跳”了一下。
7.事件托管
页面有大量元素,每个元素有一个或者多个事件句柄与之挂接(如
onclick
)时,无论怎样,你访问或者修改dom的节点时,程序就会变慢。
所以一个简单优雅的处理方式,是事件托管。他是基于这样的事实:事件逐层冒泡总能被父元素捕获。
每个事件的三个阶段:捕获->到达目标->冒泡。
<div id="downLoad">Click Me!
<a href="javascript:;">a-link</a>
<p>p标签</p>
<span>span</span>
</div>
//*********************
var odownLoad = document.getElementById("downLoad");
odownLoad.onclick = function (e) {
e=e||window.event;
var target=e.target||e.srcElement;
console.log(target.nodeName);//节点名称如 a标签 “A”,p-"P",div-"DIV";
console.log(target.href);
if(typeof e.preventDefault==="function"){ //阻止冒泡
e.preventDefault();
e.stopPropagation();
}else {
e.returnValue=false;
e.cancelBubble;
}
}
总结
- 最小化的dom访问,在javascript端做尽可能多的事。
- 在反复访问的地方使用局部变量存放dom引用。
- 小心的处理HTML集合,因为他们表现出“存在性”,总是对底层文档重新查询。将集合的length属性缓存到一个变量中,在迭代中使用这个变量。如果经常操作这个集合,可以将集合copy到数组中。
- 如果可能的话,使用速度更快的API,如
//querySelectorAll(); //querySelector()//fistElemnetChild;
- 注意页面重绘和重排版;批量修改风格,离线操作dom树,缓存并减少对局部信息的访问。
- 动画使用绝对定位,并使用拖放处理。
- 使用时间托管来最小化时间句柄数量。