模拟兼容性的 addDOMLoadEvent 事件

作者:blank 来源:怿飞blog 时间:2009-07-31 12:37:00 

由于 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);
}

怿飞提示:

  1. 如果脚本是动态注入到页面上,则原生的 DOMContentReady 事件是不会被触发(即:IE 除外)。

  2. IE 下对于在 iframe 里的使用 addDOMLoadEvent 事件,需做处理和慎用(这一点 YUI 做得不如 JQuery 细致)。

// 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();
    }
});

标签:浏览器,addDOMLoadEvent,事件,兼容性
0
投稿

猜你喜欢

  • 我是如何从玩Photoshop变成老板的

    2008-04-10 11:33:00
  • numpy矩阵数值太多不能全部显示的解决

    2023-09-09 13:55:41
  • SqlServer 2005 T-SQL Query 学习笔记(2)

    2024-01-20 20:21:51
  • 使用Javascript动态增加,删除表格

    2008-02-03 19:15:00
  • OpenCV 图像梯度的实现方法

    2023-07-14 08:25:43
  • 3个JS控制图片滚动的效果

    2007-10-23 13:40:00
  • socket + select 完成伪并发操作的实例

    2022-05-09 14:23:32
  • 详解python实现线程安全的单例模式

    2021-05-02 08:57:02
  • php版微信支付api.mch.weixin.qq.com域名解析慢原因与解决方法

    2023-07-16 11:36:01
  • php 常用类整理

    2024-05-09 14:46:57
  • 页面重构应注意的repaint和reflow

    2011-03-31 17:11:00
  • Python将文字转成语音并读出来的实例详解

    2021-11-08 21:23:34
  • 保护MySQL数据库中重要数据的注意事项

    2009-01-19 11:55:00
  • SQL SERVER 与ACCESS、EXCEL的数据转换

    2024-01-18 04:24:40
  • JScript下Array对象的性能问题

    2009-02-15 12:28:00
  • 基于vue-ssr的静态网站生成器VuePress 初体验

    2024-05-09 09:32:38
  • 关于python pycharm中输出的内容不全的解决办法

    2023-09-23 16:45:26
  • 将 Ubuntu 16 和 18 上的 python 升级到最新 python3.8 的方法教程

    2022-12-16 07:50:17
  • 使用pandas将numpy中的数组数据保存到csv文件的方法

    2023-07-17 15:27:38
  • python 中os模块os.path.exists()的用法说明

    2022-04-30 01:22:26
  • asp之家 网络编程 m.aspxhome.com