如何在窗口加载前和DOM加载后执行代码?

31

以下是情况描述: 我有两个页面:

  • 1个 HTML 页面
  • 1个外部 JavaScript

现在,在 HTML 页面中,会有内部 JavaScript 代码允许放置 window.onload,和其他页面特定的方法/函数。

但是,在外部 JavaScript 中,我希望在触发 window.onload 事件之前完成某些任务。这是为了先初始化自定义组件。

有没有一种方式可以确保在触发 window.onload 事件之前在外部 JavaScript 中进行初始化?

我提出这个问题的原因是尝试制作可重用代码(只需构建一次 - 到处使用),并且外部脚本必须检查它是否已经在主 HTML / JSP / ASP / PHP 页面中运行。而且我不想要 jQuery 的解决方案 @_@

以下是我在 Stack Overflow 上浏览的一些链接,希望能找到解决方案:

有人可以帮忙或指导我找到解决方案吗?非常感谢你们的帮助。


[更新回复 - 2012年11月19日]

大家好,感谢您的建议和提供的解决方案,在寻找和测试可行解决方案方面都很有用。 尽管我对自己的结果不是百分之百满意,但我知道您的建议和帮助已经让我更接近一个解决方案,并且可能会帮助其他处于类似情况的人。

下面是我想出的解决方案:

test_page.html

<html>
<head>
<title></title>
<script type="text/javascript" src="loader.js"></script>
<script type="text/javascript" src="test_script_1.js"></script>
<script type="text/javascript" src="test_script_2.js"></script>
<script type="text/javascript">
window.onload = function() {
    document.getElementById("div_1").innerHTML = "window.onload complete!";
}
</script>

<style type="text/css">
div {
    border:thin solid #000000;
    width:500px;
}
</head>
<body>
    <div id="div_1"></div>

    <br/><br/>

    <div id="div_2"></div>

    <br/><br/>

    <div id="div_3"></div>
</body>
</html>

加载器.js

var Loader = {
    methods_arr : [],

    init_Loader : new function() {
        document.onreadystatechange = function(e) {
            if (document.readyState == "complete") {
                for (var i = 0; i < Loader.methods_arr.length; i++) {
                    Loader.method_arr[i]();
                }
            }
        }
    },

    load : function(method) {
        Loader.methods_arr.push(method);
    }
}

test_script_1.js

Loader.load(function(){initTestScript1();});

function initTestScript1() {
    document.getElementById("div_1").innerHTML = "Test Script 1 Initialized!";
}

测试脚本2.js

Loader.load(function(){initTestScript2();});

function initTestScript2() {
    document.getElementById("div_2").innerHTML = "Test Script 2 Initialized!";
}

这将确保在调用window.onload事件处理程序之前首先调用脚本,同时还确保文档首先被渲染。

你觉得这个解决方案怎么样?

再次感谢大家的帮助 :D

4个回答

24

基本上,您正在寻找这个:

document.onreadystatechange = function(e)
{
    if (document.readyState === 'complete')
    {
        //dom is ready, window.onload fires later
    }
};
window.onload = function(e)
{
    //document.readyState will be complete, it's one of the requirements for the window.onload event to be fired
    //do stuff for when everything is loaded
};

查看MDN以获取更多细节。

请记住,DOM可能已经加载,但这并不意味着外部js文件已经加载,因此您可能无法访问在该脚本中定义的所有函数/对象。如果您想要检查这一点,您需要使用window.onload,以确保所有外部资源也已被加载。

所以,在您的外部脚本中,您将需要2个事件处理程序:一个用于readystatechange,它会在DOM准备就绪时完成您需要完成的操作,另一个是window.onload,它将在文档准备就绪后被触发。(这检查页面是否完全加载)。 只要您知道,在IE<9中,window.onload会导致内存泄漏(因为DOM和JScript引擎是两个独立的实体,窗口对象永远不会完全卸载,并且侦听器不会被垃圾收集)。有一种方法可以解决这个问题,我在这里发布了,虽然有点冗长,但您应该知道...


有人能帮我理解这段代码吗?当我使用它时,它是可以工作的。但是我并没有完全理解这里的代码。哪部分应该放在 if 的条件语句中,哪部分应该放在 window.onload = function(e) 中? - theFrontEndDev

4
如果您想立即完成某些操作而不需要等待任何事件,那么您可以使用JavaScript来执行 - 您无需做任何事情即可立即运行代码,只要不进行任何会导致代码等待的操作即可。因此,这实际上比等待事件更容易。
例如,如果您有以下HTML:
<div id=one></div>
<script src="your-script.js"></script>
<div id=two></div>

如果您在代码中引用了一个外部的JavaScript文件(your-script.js),那么它将会在id为"one"的div被解析之后但在id为"two"的div之前运行。请注意,不要注册事件回调函数,而是在JavaScript中立即执行所需的操作。

3

还可以使用Window接口的DOMContentLoaded事件。

addEventListener("DOMContentLoaded", function() {
    // Your code goes here
});

上述代码实际上是将事件监听器添加到了window对象上,尽管它没有被标识为window.addEventListener,因为window对象也是网页中JavaScript代码的全局作用域。
DOMContentLoaded事件发生在load事件之前,当图像和其他部分的网页还没有完全加载时。但是,在初始调用堆栈中添加到DOM中的所有元素都保证已经被添加到其父级元素中,然后再触发此事件。
您可以在此处找到官方文档here

3

JavaScript从上至下运行。这意味着,如果您在内部JavaScript之前包括外部JavaScript,则外部JavaScript将在内部JavaScript运行之前运行。


1
并非完全正确:<script src="some/huge/script.js" async="async"></script><script>alert('foo');</script>:内部脚本将在外部文件加载之前运行。 - Elias Van Ootegem
3
没错,使用异步编程的人都知道这一点。 - GottZ
我只是想指出,从上到下的事情并不总是完整的。PS:假设使用异步的人知道这一点可能是一个危险的假设:因为他们期望AJAX同步工作,所以这里有很多关于ajax调用未设置某些变量的问题。 - Elias Van Ootegem
4
在我看来,认为Ajax应该同步工作的人应该开始学习JavaScript。 - GottZ
1
在我看来,大多数滥用JavaScript的人应该开始学习JS :). 在这方面,我赞同Douglas Crockford的观点:JS是世界上最被误解和低估的语言。 - Elias Van Ootegem

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