2010-10-19 updates
今天有网友说下面简化的版本在IE6下会触发IE6的“终止操作”的bug,测试了一下,确实存在这个问题(问题页面),所以对简化版的DOMReady进行了重构了,使用setInterval代替setTimeout就没事了,很奇怪的问题:
[javascript]
var DOMReady = {
ready: function(){
var that = DOMReady,done = false,init,args = arguments;
//ready之后统一处理函数
init = function(){
if(!done){
done = true;
(typeof args[0] === "function" ? args[0] : function(){})();
}
}
//添加DOMContentLoaded事件的支持
if (document.addEventListener) {
document.addEventListener("DOMContentLoaded", init, false);
}
//使用普通的方式进行检测
var interval = setInterval(function(){
if (document && document.getElementsByTagName && document.getElementById && document.body) {
clearInterval(interval);
init();
}
},20);
}
};
[/javascript]
或者再使用更加强健一点的方式:
[javascript]
var DOMReady = {
ready: function(){
var that = DOMReady,
done = false,
init = typeof arguments[0] === "function" ? arguments[0] : function(){},
u = navigator.userAgent;
if (/webkit/i.test(u)) {
(function(){
var dr = document.readyState;
if (dr == "loaded" || dr == "complete") {
init();
} else {
setTimeout(arguments.callee, 10);
}
})();
}else if (document.addEventListener) { //添加DOMContentLoaded事件的支持
document.addEventListener("DOMContentLoaded", init, false);
}else{
(function(){
var t = document.createElement(‘doc:rdy’);
try {
t.doScroll(‘left’);
init();
t = null;
} catch (e) {
setTimeout(arguments.callee, 0);
}
})();
}
}
};
[/javascript]
=================== 就错线 =====================
在很多javascript库中,检查DOM是否加载完成是非常重要的一个功能模块,它可以被独立出来作为一个模块来供其他对象调用,下面是我提供的一种方式,原理就是使用一个定时器来循环检查document,document.body,document.body.lastChild是否可用,从而证明DOM是否加载完成:
[javascript]
/**
* @author Supersha
* @website http://www.ilovejs.net
*/
var DOMReady = {
done: false,
ID: 0,
fn:null,
ready: function(){
this.fn = typeof arguments[0] === "function" ? arguments[0] : function(){
alert("Argument should be a function.");
};
//添加对Firefox,Opera等支持DOMContentLoaded事件的支持
if (document.addEventListener) {
document.addEventListener("DOMContentLoaded", this.fn, false);
return;
}
//持续检查DOM是否加载完成
this.ID = setInterval(this.check(this), 20);
},
check: function(obj){
return function(){
if (obj.done) {
clearInterval(obj.ID);
obj.fn();
} else if (document && document.getElementsByTagName && document.getElementById && document.body) {
obj.done = true;
}
}
}
}
[/javascript]
把DOMReady对象模块添加到其他的功能模块中就可以非常方便的去操作DOM,而无需考虑是否加载完成,比如:
[javascript]
DOMReady.ready(function(){
alert(document.getElementById("div").innerHTML);
});
[/javascript]
################ 即时更新 ####################
利用arguments.callee还能更加精简DOMReady对象的代码:
[javascript]
var DOMReady = {
ready: function(){
DOMReady .fn = typeof arguments[0] === "function" ? arguments[0] : function(){};
(function(){
if (document && document.getElementsByTagName && document.getElementById && document.body) {
DOMReady .fn();
}
else {
//利用arguments.callee获取匿名函数的引用,之后在setTimeout定时器里循环执行
setTimeout(arguments.callee, 20);
}
})();
}
};
[/javascript]