DOMContentLoaded事件与readystatechange事件

原创 pingfan 随笔 js 2160阅读 2014-08-31 10:16:06 举报

一、DOMContentLoad事件

window的load事件会在页面中的一切都加载完毕时触发,但这个过程可能会因为要加载的外部资源过多而破费周折。而DOMContentLoaded事件则在形成完整地Dom树之后就会触发,不理会图像、javascript文件、css文件或其他资源是否已经下载完毕。与load事件不同,DOMContentLoaded支持在页面下载的早期添加事件处理程序,这也就意味着用户能够尽早地与页面进行交互。

要处理DOMContentLoad事件,可以为document或window添加相应的事件处理程序(尽管这个事件会冒泡到window,但它的目标实际上是document)。来看下面的例子:

[code] var EventUtil={
addHandler:function(element,type,handler){
if(element.addEventListener){
element.addEventListener(type,handler,false);
}else if(element.attachEvent){
element.attachEvent("on"+type,handler);
}else{
element["on"+type]=handler;
}
},
removeHandler:function(element,type,handler){
if(element.removeEventListener){
element.removeEventListener(type,handler,false);
}else if(element.detachEvent){
element.detachEvent('on'+type,handler);
}else{
element["on"+type]=null;
}
}
}

    EventUtil.addHandler(document,"DOMContentLoaded",function(event){
        alert("Dom 节点已经加载完成");

})
[/code]

DOMContentLoaded事件对象不会提供任何额外信息(其target属性是document)。

IE9、FireFox、chrome、safari3.1+和Opera9+都支持DOMContentLoaded事件,通常这个事件既可以添加事件处理程序,也可以执行其他DOM操作。这个事件始终都会在load事件之前触发。

[color=Red]为了解决ie8以下监测DOM加载情况,出现了readystatechange事件。[/color]

二、readyStatechange事件

IE为DOM文档中的某些部分提供了readystatechange事件。这个事件的目的是提供与文档或元素的加载状态有关的信息。但这个事件的行为有些时候也很难预料。支持readystatechange事件的每个对象都有一个readystate属性,可能包含下列5个值中的一个。

uninitialized(未初始化):对象存在但尚未初始化。

loading(正在加载):对象正在加载数据。

loaded(加载完成):对象加载数据完成。

interactive(交互):可以操作对象了,但还没有完全加载。

complete(完成):对象已经加载完毕。

这些状态看起来很直观,但并非所有对象都会经历readyState的这几个阶段。换句话说,如果某个阶段不适合某个对象,则该对象完全可能跳过该阶段;并没有规定那个阶段适用于那个对象。显然,这意味着readystatechange事件经常会少于4次,而readystate属性的值也不总是连续的。

对于document而言,值为"interactive"的readyState会在与DOMContentLoaded大致相同的时刻触发readystatechange事件。此时,DOM树已经加载完毕,可以安全地操作它了,因此就会进入交互(interactive)阶段。但与此同时,图像及其它外部文件不一定可用。下面来看一段处理readystatechange事件的代码。

[code] EventUtil.addHandler(document,"readystatechange",function(event){
if(document.readystate == "interactive"){
alert("DOM树已经加载完毕");
}
})[/code]

这个事件的event对象不会提供任何信息的,也没有目标对象。

在与load事件一起使用时,无法预测两个事件触发的先后顺序。在包含较多或较大的外部资源的页面中,会在load事件触发之前先进入交互阶段;

让问题变得更复杂的是,交互阶段可能会早于也可能会晚于完成阶段出现,无法确保顺序。在包含较多外部资源的页面中,交互阶段更有可能早于完成阶段出现;而在页面中包含较少外部资源的情况下,完成阶段先于交互阶段出现的可能性更大。因此,为了尽可能抢到先机,有必要同时检测交互和完成阶段,如下例子所示

[code] EventUtil.addHandler(document,readystatechange,function(){
if(document.readyState=='loaded' || document.readyState=="complete"){
EventUtil.removeHandler(documeng,readystatechange,arguments.callee);
alert("DOM树已经加载完毕");
}
})
[/code]

对于上面的代码来说,当readystatechange事件触发时,会检测document.readystate的值,看当前是否已经进入交互阶段或完成阶段。如果是,则移除相应的事件处理程序以免在其他阶段在执行。注意,由于事件处理程序使用的是匿名函数,因此这里使用了arguments.callee来引用该函数。然后,会显示一个警告框,说明内容已经加载完毕。这样编写代码可以达到与使用DOMContentLoaded十分相近的效果。

支持readystatechange事件的浏览器有IE、firefox4和Opera。

[color=Red]注意[/color]:虽然使用readystatechange可以十分近似地模拟DOMContentLoaded事件,但他们本质上还是不同的。在不同页面中,load事件与readystatechange事件并不能保证以相同的顺序触发。

三、额外补充

<script>(在IE和opera中)和<link>(仅IE中)元素也会触发readystatechange事件,可以用来确定外部javascript和css文件是否已经加载完成。与其他浏览器中一样,除非把动态创建的元素添加到页面中,否则浏览器不会开始下载外部资源。基于元素触发的readystatechange事件存在同样地问题,即readystate属性无论等于”loaded“还是”completed“都可以表示资源已经可用。有时候,readyState会停在”loaded“阶段永远不会”完成“;有时候,又会跳过”loaded“阶段而直接”完成“。于是,还需要对待document一样采取相同的编码方式。例如,加载外部javascript代码:

[code]
EventUtil.addHandler(window,"loaded",function(){
var script=document.createElement("script");
EventUtil.addHandler(script,"readystatechange",function(event){
event=EventUtil.getEvent(event);
var target=EventUtil.getTarget(event);

        if(target.readyState == "loaded" || target.readyState == "complete"){
            EventUtil.removeHandler(target,"readystatechange",arguments.callen);
            alert("script loaded");
    }
});
    script.src="pingfan.js";
    document.body.appendChild(script);

});[/code]

同样方式加载样式css:

[code] EventUtil.addHandler(window,"loaded",function(){
var link=document.createElement("script"),
link.type='text/css',
link.rel="sheetstyle";
EventUtil.addHandler(link,"readystatechange",function(event){
event=EventUtil.getEvent(event);
var target=EventUtil.getTarget(event);

        if(target.readyState == "loaded" || target.readyState == "complete"){
            EventUtil.removeHandler(target,"readystatechange",arguments.callen);
            alert("css loaded");
    }
});
    link.href="pingfan.css";
    document.getElementsByTagName('head')[0].appendChild(css);

});[/code]

评论 ( 0 )
最新评论
暂无评论

赶紧努力消灭 0 回复