<body>.onLoad在渲染完成前被调用吗?

6

我希望在页面加载后调用一些JS,这可能涉及延迟,因此我希望先加载页面以显示内容...但似乎在渲染完成之前就调用了onLoad处理程序中的代码。是否有更好的事件可以使用,可以在页面“完成”时触发?

澄清一下,我想在页面在屏幕上呈现后运行一些JS,所以实际上是一个“后-everything事件”。


如果您的页面完全呈现,然后您的Javascript操作DOM,您将看到未操作的DOM的“闪烁”,然后更改将显示出来。但是,onload应该在所有图像下载完成等之后才被调用... - justkt
所以...你想要在DOM准备就绪或所有资源加载完后运行你的代码。很抱歉,但我不清楚。 - Felix Kling
基本上,当我看到面前的页面时,我想要运行一些代码。 - Mr. Boy
@John:“onLoad处理程序在呈现完成之前被调用。”据我所知,在“onload”之后,布局已经确定并且所有元素结构已经完成。您有什么经验使您认为不是这样?其他信号是“ondomcontentloaded”和“onpageshow”。但是,由于许多浏览器的许多版本不会触发它们(特别是“onpageshow”,通常限于“bfcache”功能),因此最大限度地提高了跨浏览器兼容性。jQuery概括解决了跨浏览器问题,但请注意,它是针对“DOM Ready”,而不是完全显示。 - Chuck Kollars
5个回答

6
有几个时间点值得注意。尽管不同的浏览器和版本实现细节有所不同,但这个通用的顺序是一个很好的概述。(假设你正在使用原始JavaScript并需要最小化跨浏览器问题;由于其全面处理跨浏览器问题的内部机制,JQuery略有不同):
T0] 页面开始-浏览器已经开始处理页面,但环境仍在变化。您的JS操作可能发生在错误的上下文中,并在正确的上下文稳定之后被清除。您可能根本不想尝试执行任何JS。
T1] "onLoad"事件- [无论您如何获取事件:addEventListener("Load"...,window.onload=...等]页面的所有部分都已从服务器识别并下载到本地系统的内存中。为了识别所有部分,已经进行了一些解析。(请注意,“load”是“download”的同源词,而不是“parse”或“render”。)
现在您拥有正确的环境,并可以开始执行JS代码,而不必担心丢失任何内容。然而,试图读取或操作HTML [getElementById(...,appendChild(...等]的操作可能会以奇怪的方式失败,或者可能看起来工作正常,但随后消失,或者可能执行与您预期不同的操作。
T2] DOM-几乎准备就绪-这个hack非常简单,完全跨浏览器。只需将您的JS <script>...</script>放在HTML的最后一个位置,在</body>标记之前。大多数事情都会正常工作,尽管尝试附加或修改DOM在<body>的最后可能会产生令人惊讶的结果。这不是完全正确的,但它99%的时间都有效。鉴于其简单性和非常高的正确操作概率,这可能是一种可行的方式(至少如果您不使用JQuery)。
T3] DOM就绪- [无论您如何获取事件:addEventListener("DOMContentLoaded"...,window.ondomcontentloaded=...等]此时HTML已完全解析,JS 100%可用,包括所有读取或操作HTML [getElementById(...,appendChild(...等]的函数。
T4] 渲染完成-浏览器已经完成在屏幕上显示内容。没有任何这样的事件或任何合理的跨浏览器版本不可知的方法来检测这种情况。这也很好,因为您可能真的不想要这个。如果浏览器已经在屏幕上显示了页面,然后您操作DOM,您将得到一个“闪烁”,其中屏幕上的前后两个部分至少短暂可见。您可能真正想要的是可以执行任意JS代码的点;那是之前(T3] DOM就绪)的时间点。

这个答案还正确吗?根据这张图片显示,onLoad事件发生在onDOMContentLoaded之后。 - howard_9
这个答案还正确吗?根据这个图片,onLoad事件发生在onDOMContentLoaded事件之后。 - undefined
答案取决于浏览器和版本。DOMContentLoaded事件似乎从未得到充分的标准化,并且许多当前(2023年6月)的浏览器根本不会触发该事件。如果确实触发了该事件,我相信它将在Load事件之前被触发;所引用的图片是错误的。要了解任何特定浏览器的真正行为,请启动感兴趣的浏览器并将其指向https://www.ckollars.org/browser-page-events.html。 - Chuck Kollars
答案取决于浏览器和版本。DOMContentLoaded事件似乎从未得到充分的标准化,并且许多当前的浏览器(截至2023年6月)根本不会触发该事件。如果确实触发了DOMContentLoaded事件,我相信它会在Load事件之前触发;所提及的图片是错误的。要了解任何特定浏览器的真实行为,请启动感兴趣的浏览器并将其指向https://www.ckollars.org/browser-page-events.html。 - undefined

3

Either attach a callback to window.onload

window.onload = function(){
    // your code here
};

当所有资源都加载完成时,此代码将被触发(可能不是您想要的)。

或者将所有代码放在页面底部(在结束的body标签之前)。该代码将在HTML解析时运行。


顺便提一下,这是jQuery代码。你会看到,它使用自定义事件处理程序来处理IE和其他浏览器,但将window.onload作为备用方案:

// Mozilla, Opera and webkit nightlies currently support this event
if ( document.addEventListener ) {
    // Use the handy event callback
    document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );

    // A fallback to window.onload, that will always work
    window.addEventListener( "load", jQuery.ready, false );

    // If IE event model is used
} else if ( document.attachEvent ) {
    // ensure firing before onload,
    // maybe late but safe also for iframes
    document.attachEvent("onreadystatechange", DOMContentLoaded);

    // A fallback to window.onload, that will always work
    window.attachEvent( "onload", jQuery.ready );

    // If IE and not a frame
    // continually check to see if the document is ready
    var toplevel = false;

    try {
        toplevel = window.frameElement == null;
    } catch(e) {}

    if ( document.documentElement.doScroll && toplevel ) {
        doScrollCheck();
    }
}

@StuperUser:不知道它是否在完全相同的点上引发(根据规范应该是这样),但它是在 DOM 可用的时候引发的。 - Felix Kling
我已经使用了 onLoad,但在任何浏览器中都无法正常工作... 当 JS 被调用时,我的基本 HTML 是 不可见 的,而且由于 JS 在进行一些繁重的操作,页面会停顿。这很可能是 JS 的错误使用方式,但无论如何,在方法触发之前,页面应该被渲染出来... 这就是我需要的。 - Mr. Boy
@John:你试过在HTML页面底部添加代码吗?确定你设置了正确的代码吗?你能提供你的页面链接吗? - Felix Kling

0

和很多 JavaScript 一样,这取决于您使用的浏览器。

像 @Avitus 回答中所说,您是否查看了 JQuery 文档就绪事件的执行点?这已经被泛化到所有浏览器上。


0
如果您计划使用JavaScript库(如jQuery),我建议使用$(document).ready()语句,该语句在DOM准备好进行操作时调用。
另一个选择是将函数调用包含在HTML页面的末尾,以便加载所有HTML内容,因此您可以安全地执行代码。

0

"onload事件会等待所有二进制内容下载完成后再触发。在此之前不要逗猫玩。"

正如本文所述,它会在所有二进制内容下载完成后被调用,您需要使用jQuery的ready或自己的函数来监听ready事件。这个项目看起来很有趣。

有许多跨浏览器的实现,因此请使用jQuery或我链接到的那个项目。

我为我的库编写了自己的函数,它使用内部方法,因此无法单独使用,但可能会让您了解需要做什么。您可以在这里找到该函数。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接