在传统事件模型中,load是页面中最早被触发的事件。不过当使用load事件来初始化页面时可能会存在一个问题,那就是当页面中包含很大的文件时,load事件需要等到所有图像全部载入完成之后才会被触发。这时可以考虑使用DOMContentLoaded事件,作为DOM标准事件,它是在DOM文档结构加载完毕的时候被触发的,要比load事件先被触发。目前,Firefox和Opera新版本已经支持了DOMContentLoaded事件,而IE和Safari浏览器还不支持。
在标准DOM中可以这样设计:
<html>
<head>
<script language="javascript"type="text/javascript">
window.onload=f1;
if(document.addEventListener){
document.addEventListener("DOMContentLoaded",f,false);
}
function f{
alert("我提前执行了");
}
function f1{
alert("页面初始化完毕");
}
</script>
</head>
<body>
<img src="Winter.jpg">
</body>
</html>
这样,在图片加载之前,会弹出“我提前执行了”的提示信息,而在图片加载完毕后才会弹出“页面初始化完毕”提示信息。这说明在页面HTML结构加载完毕之后触发DOMContentLoaded事件,也就是说,在文档标签加载完毕触发该事件,并调用函数f,然后在文档所有内容加载完毕(包括图片下载完毕)才触发load事件,并调用函数f1。
由于IE不支持DOMContentLoaded事件,为了实现兼容处理,我们需要运用一点小技巧,即在文档中写入一个新的script元素,不过该元素会延迟到文件最后加载。在使用script元素的onreadystatechange方法进行类似的readyState检查后及时调用载入事件,代码如下:
if(window.ActiveXObject){
document.write("<script id=ie_onload defer src=javascript:void(0)><//script>");
document.getElementById("ie_onload").onreadystatechange=function{
if(this.readyState=="complete"){
this.onreadystatechange=null;
f;
}
}
}
在写入的<script>标签中包含了defer属性,defer表示“延期”的意思,使用defer属性可以让脚本在整个页面加载完成之后再解析,而非边加载边解析。这对于只包含事件触发的脚本来说,可以提高整个页面的加载速度。与src属性联合使用,还可以使这些脚本在后台被下载,前台的内容则正常显示给用户。目前只有IE支持defer属性。在定义了defer属性后,<script>标签中就不应该包含document.write命令了,因为document.write将产生直接输出效果,并且不包括任何立即执行脚本要使用的全局变量或函数。
由于<script>标签在文档结构加载完毕之后才加载,因此只要判断它的状态就可以确定当前文档结构是否已经加载完毕,并触发响应的事件。
针对Safari浏览器,我们可以使用setInterval函数周期性地检查document对象的readyState属性,随时监控文档是否加载完毕,如果加载完成则调用回调函数,代码如下:
if(/WebKit/i.test(navigator.userAgent)){
var_timer=setInterval(function{
if(/loaded|complete/.test(document.readyState)){
clearInterval(_timer);
f;
}
},10);
}
把上面3段条件结构合并在一起即可实现兼容不同浏览器的DOMContentLoaded事件处理函数。