关于javascript:页面DOM加载后(但在window.onload之前)获得通知

关于javascript:页面DOM加载后(但在window.onload之前)获得通知

Getting notified when the page DOM has loaded (but before window.onload)

我知道有一些方法可以在页面主体加载时得到通知(在加载所有图像和第3方资源之前,这会触发window.onload事件),但是对于每个浏览器来说都是不同的。

在所有浏览器上都有确定的方法吗?

到目前为止,我知道:

  • DOMContentLoaded:在Mozilla,Opera 9和最新的WebKit上。这涉及向事件添加侦听器:

    document.addEventListener(" DOMContentLoaded",[init函数],false);

  • 延迟脚本:在IE上,您可以发出带有@defer属性的SCRIPT标记,该标记只有在关闭BODY标记后才能可靠地加载。

  • 轮询:在其他浏览器上,您可以继续进行轮询,但是甚至没有标准的东西可以轮询,还是需要在每个浏览器上执行不同的操作?

我希望能够不使用document.write或外部文件。

这可以简单地通过jQuery完成:

1
$(document).ready(function() { ... })

但是,我正在写一个JS库,不能指望jQuery总是在那里。


没有跨浏览器的方法可以检查DOM是否准备就绪-这就是为什么存在jQuery之类的库来抽象出讨厌的一点不兼容的原因。

Mozilla,Opera和现代WebKit支持DOMContentLoaded事件。 IE和Safari需要怪异的技巧,例如滚动窗口或检查样式表。血腥的细节包含在jQuery的bindReady()函数中。


我找到了此页面,该页面显示了一个紧凑的独立解决方案。它似乎可以在每种浏览器上运行,并说明了如何:

http://www.kryogenix.org/days/2007/09/26/shortloaded


使用类似jQuery的库将为您节省无数小时的浏览器不一致问题。

在这种情况下,您可以使用jQuery

1
2
3
$(document).ready ( function () {
    //your code here
});

如果您感到好奇,可以看一下资料来源,看看它是如何完成的,但是在如今的这个时代,我认为当图书馆作家为您完成所有痛苦的工作时,没有人应该重新发明这个轮子。


YUI使用三??个测试来执行此操作:对于Firefox和最近的WebKit,将触发一个DOMContentLoaded事件。对于较旧的Safari,document.readyState会一直监视,直到"加载"或"完成"为止。对于IE,HTML

标签已创建,并且调用了" doScroll()"方法,如果DOM未准备好,该方法应该会出错。 YAHOO.util.Event的源显示了特定于YUI的代码。在Event.js中搜索" doScroll"。


只需从jQuery中获取相关代码,John Resig就已经涵盖了jQuery中有关此问题的大部分基础。


您正在寻找的花哨的浏览器解决方案...不存在...(想象一大群人在说" aahhhh ...."的声音)。

DomContentLoaded只是您的最佳选择。对于IE-oldies,您仍然需要polling技术。

  • 尝试使用addEventListener;
  • 如果不可用(显然是IE),请检查帧;
  • 如果不是框架,请滚动直到没有错误(轮询);
  • 如果是框架,请使用IE事件document.onreadystatechange;。
  • 对于其他不支持的浏览器,请使用旧的document.onload事件。
  • 我在javascript.info上找到了以下代码示例,可用于覆盖所有浏览器:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    function bindReady(handler){

        var called = false

        function ready() {
            if (called) return
            called = true
            handler()
        }

        if ( document.addEventListener ) { // native event
            document.addEventListener("DOMContentLoaded", ready, false )
        } else if ( document.attachEvent ) {  // IE

            try {
                var isFrame = window.frameElement != null
            } catch(e) {}

            // IE, the document is not inside a frame
            if ( document.documentElement.doScroll && !isFrame ) {
                function tryScroll(){
                    if (called) return
                    try {
                        document.documentElement.doScroll("left")
                        ready()
                    } catch(e) {
                        setTimeout(tryScroll, 10)
                    }
                }
                tryScroll()
            }

            // IE, the document is inside a frame
            document.attachEvent("onreadystatechange", function(){
                if ( document.readyState ==="complete" ) {
                    ready()
                }
            })
        }

        // Old browsers
        if (window.addEventListener)
            window.addEventListener('load', ready, false)
        else if (window.attachEvent)
            window.attachEvent('onload', ready)
        else {
            var fn = window.onload // very old browser, copy old onload
            window.onload = function() { // replace by new onload and call the old one
                fn && fn()
                ready()
            }
        }
    }


    为什么不这样:

    1
    2
    3
    4
    5
    6
    7
    8
    <body>  
      <!-- various content -->  
      <script type="text/javascript">  
      <!--  
        myInit();  
      -->
       
    </body>

    如果我理解正确,那么只要浏览器在页面中击中myInit,它就会立即执行,这是体内的最后一件事。


    尽管执行时间取决于浏览器,但使用setTimeout可以很好地工作。如果您将超时时间设置为零,则在"解决"问题时浏览器将执行。

    这样做的好处是您可以拥有许多控件,而不必担心链接onLoad事件。

    1
    2
    3
    setTimeout(myFunction, 0);
    setTimeout(anotherFunction, 0);
    setTimeout(function(){ doSomething ...}, 0);

    等等

    它们将在文档加载完成后全部运行,或者如果您在文档加载后进行设置,它们将在脚本运行完之后运行。

    它们的运行顺序不确定,并且可以在浏览器之间更改。因此,例如,您不能指望myFunctionanotherFunction之前运行。


    效果很好:

    1
    setTimeout(MyInitFunction, 0);

    推荐阅读