由于 window.onload
事件需要在页面所有内容(包括图片等)加载完后,才执行,但往往我们更希望在 dom 一加载完就执行脚本。其实在现在大部分主流浏览器上(firefox 3+,opera 9+,safari 3+,chrome 2+)都提供了这一事件方法:adddomloadevent
。
document.addeventlistener("domcontentloaded", init, false);
那对于 ie 我们如何模拟 adddomloadevent 事件呢?
matthias miller 最早提供了如下的解决方案:
// for internet explorer (using conditional comments)
/*@cc_on @*/
/*@if (@_win32)
document.write("<script id=__ie_onload defer src=javascript:void(0)><//script>");
var script = document.getelementbyid("__ie_onload");
script.onreadystatechange = function() {
if (this.readystate == "complete") {
init(); // call the onload handler
}
};
/*@end @*/
而 diego perini 在其后提供了一种利用 doscroll()
方法来模拟 adddomloadevent 事件的方案,且现在主流的 javascript 框架(jquery、yui等)基本都采用的这一解决方案。
原理基本如下:
当 ondocumentready 事件触发,文档( document )已经完全解析和建立。如果组件需要操作最初的文档结构,初始化代码需被安置在这之后。ondocumentready 事件告知组件,整个页面已被加载,且在 初始文档的 onload 事件触发之前立即触发。
一些方法,例如 doscroll,要求最初的文档被完全加载。如果这些方法是初始化函数的一部分,当ondocumentready 事件触发,他们将被执行。
/*
*
* iecontentloaded.js
*
* author: diego perini (diego.perini at gmail.com) nwbox s.r.l.
* summary: domcontentloaded emulation for ie browsers
* updated: 05/10/2007
* license: gpl/cc
* version: tbd
*
*/
// @w window reference
// @fn function reference
function iecontentloaded (w, fn) {
var d = w.document, done = false,
// only fire once
init = function () {
if (!done) {
done = true;
fn();
}
};
// polling for no errors
(function () {
try {
// throws errors until after ondocumentready
d.documentelement.doscroll('left');
} catch (e) {
settimeout(arguments.callee, 50);
return;
}
// no errors, fire
init();
})();
// trying to always fire before onload
d.onreadystatechange = function() {
if (d.readystate == 'complete') {
d.onreadystatechange = null;
init();
}
};
}
jquery 1.3.2 中源码实现如下:
// if ie and not an iframe
// continually check to see if the document is ready
if ( document.documentelement.doscroll && window == window.top ) (function(){
if ( jquery.isready ) return;
try {
// if ie is used, use the trick by diego perini
// http://javascript.nwbox.com/iecontentloaded/
document.documentelement.doscroll("left");
} catch( error ) {
settimeout( arguments.callee, 0 );
return;
}
// and execute any waiting functions
jquery.ready();
})();
yui 2.7.0 中源码实现如下:
if (eu.isie) {
// process onavailable/oncontentready items when the
// dom is ready.
yahoo.util.event.ondomready(
yahoo.util.event._trypreloadattach,
yahoo.util.event, true);
var n = document.createelement('p');
eu._dri = setinterval(function() {
try {
// throws an error if doc is not ready
n.doscroll('left');
clearinterval(eu._dri);
eu._dri = null;
eu._ready();
n = null;
} catch (ex) {
}
}, eu.poll_interval);
}
另外对于版本小于 safari 3+ 的 safari 浏览器,john resig 也提供了一个解决方案:
if (/webkit/i.test(navigator.useragent)) { // sniff
var _timer = setinterval(function() {
if (/loaded|complete/.test(document.readystate)) {
clearinterval(_timer);
init(); // call the onload handler
}
}, 10);
}
怿飞提示:
// form jquery 1.3.2
// ensure firing before onload, maybe late but safe also for iframes
document.attachevent("onreadystatechange", function(){
if ( document.readystate === "complete" ) {
document.detachevent( "onreadystatechange", arguments.callee );
jquery.ready();
}
});
扩展阅读:
新闻热点
疑难解答