关于DOMContentLoaded
也许还有朋友不太清楚DOMContentLoaded这个事件。简单的说,这个事件就是要在大多数情况下去替代window.onload事件,因为window.onload事件必须要等待页面所有元素的资源都下载完毕时才触发。
这个事件实际是上w3c推荐的标准事件,是在DOM树建成的时候触发,因此要比onload事件快很多。ff, opera高版本已经支持了该事件。而IE在IE8里依然没有想加这个事件的意思,为了实现IE与w3c的兼容,我们有必要为IE做一件“好事”。
一般是两种方法。
- 一种是创建空script标签,属性拥有defer,然后待onreadystatechange为complete时激发DOMContentLoaded
- 一种是通过调用doScroll('left')的原理去判断DOMContentLoaded
第一种方法
<script type="text/javascript">//<![CDATA[
var $ = document.getElementById;
var fireDOMReadyEvent = function () {
alert('DOM content loaded----------------http://www.never-online.net/blog/');
}
if (!!window.ActiveXObject) {
// Internet Explorer use defer attribute
var src = (window.location.protocol == 'https') ? '://0' : 'javascript:void(0)';
document.write('<SCRIPT id=____dom_content_ready__ src="' + src + '" defer><\/script>');
$('____dom_content_ready__').onreadystatechange = function() {
if (this.readyState == 'complete') {
this.onreadystatechange = null;
fireDOMReadyEvent();
}
};
}
//]]></script>
<body>
<img src="http://img9.zol.com.cn/desk_pic/big_304/303619.jpg">
</body>
var $ = document.getElementById;
var fireDOMReadyEvent = function () {
alert('DOM content loaded----------------http://www.never-online.net/blog/');
}
if (!!window.ActiveXObject) {
// Internet Explorer use defer attribute
var src = (window.location.protocol == 'https') ? '://0' : 'javascript:void(0)';
document.write('<SCRIPT id=____dom_content_ready__ src="' + src + '" defer><\/script>');
$('____dom_content_ready__').onreadystatechange = function() {
if (this.readyState == 'complete') {
this.onreadystatechange = null;
fireDOMReadyEvent();
}
};
}
//]]></script>
<body>
<img src="http://img9.zol.com.cn/desk_pic/big_304/303619.jpg">
</body>
看上去应该没有什么问题了。但实际在使用当中还是遇到不少的问题,主要是协议,还有iframe。https协议需要单独判断。
iframe的问题在Jerry使用的时候发现比较大的问题,比如
<script type="text/javascript">//<![CDATA[
var $ = document.getElementById;
var fireDOMReadyEvent = function () {
alert('DOM content loaded----------------http://www.never-online.net/blog/');
}
if (!!window.ActiveXObject) {
// Internet Explorer use defer attribute
var src = (window.location.protocol == 'https') ? '://0' : 'javascript:void(0)';
document.write('<SCRIPT id=____dom_content_ready__ src="' + src + '" defer><\/script>');
$('____dom_content_ready__').onreadystatechange = function() {
if (this.readyState == 'complete') {
this.onreadystatechange = null;
fireDOMReadyEvent();
}
};
}
//]]></script>
<iframe src="http://www.csdn.net"></iframe>
var $ = document.getElementById;
var fireDOMReadyEvent = function () {
alert('DOM content loaded----------------http://www.never-online.net/blog/');
}
if (!!window.ActiveXObject) {
// Internet Explorer use defer attribute
var src = (window.location.protocol == 'https') ? '://0' : 'javascript:void(0)';
document.write('<SCRIPT id=____dom_content_ready__ src="' + src + '" defer><\/script>');
$('____dom_content_ready__').onreadystatechange = function() {
if (this.readyState == 'complete') {
this.onreadystatechange = null;
fireDOMReadyEvent();
}
};
}
//]]></script>
<iframe src="http://www.csdn.net"></iframe>
它会在iframe加载完毕的时候才触发事件,显然不是我们所需要的。
也因为如此,我们现在很流行第二种方案:用doScroll方法。这主要是利用doScroll是是DOM树形成之后才可以操作。
<script type="text/javascript">//<![CDATA[
var $ = document.getElementById;
var fireDOMReadyEvent = function () {
window.clearInterval(timer)
alert('DOM content loaded----------------http://www.never-online.net/blog/');
}
if (!!window.ActiveXObject) {
// Using doScroll method to instead of script tag to deal with DOM content loaded event
var timer = null;
timer = setInterval(function () {
try {
document.body.doScroll('left');
fireDOMReadyEvent();
} catch(ex) {};
});
}
//]]></script>
<iframe src="http://www.csdn.net"></iframe>
<img src="http://img9.zol.com.cn/desk_pic/big_304/303619.jpg">
var $ = document.getElementById;
var fireDOMReadyEvent = function () {
window.clearInterval(timer)
alert('DOM content loaded----------------http://www.never-online.net/blog/');
}
if (!!window.ActiveXObject) {
// Using doScroll method to instead of script tag to deal with DOM content loaded event
var timer = null;
timer = setInterval(function () {
try {
document.body.doScroll('left');
fireDOMReadyEvent();
} catch(ex) {};
});
}
//]]></script>
<iframe src="http://www.csdn.net"></iframe>
<img src="http://img9.zol.com.cn/desk_pic/big_304/303619.jpg">
以前听同事提过在YUI里有两种ready事件,一种是DOMContentLoaded,一种是ElementReadyContentReady(怿飞提醒,修正)。还没有详细的去看代码,有兴趣的朋友也可看一下。
今天顺便看了一下YUI,判断DOMContentLoaded,大概是这样。
var p = document.createElement('p');
p.doScroll('left');
fireDOMLoadedHandle();
p.doScroll('left');
fireDOMLoadedHandle();
个人认为此方法有一个问题,p在IE6下是不会释放的,所以会有memory leak。
而mootools里的方法也是有问题的:
var el = document.createElement('div');
document.body.appendChild(el);
el.innerHTML = "left";
el.parentNode.removeChild(el);
clearInterval(interval);
ready();
document.body.appendChild(el);
el.innerHTML = "left";
el.parentNode.removeChild(el);
clearInterval(interval);
ready();
IE6下假如是在body未在加完之前运行会有,HTML无法结束的警告。(具体出错信息记不清了-_-!)