使用window.onload的最佳实践

40

我开发Joomla网站/组件/模块和插件,有时需要使用在页面加载时触发事件的JavaScript。大多数情况下,可以使用window.onload函数实现。

我的问题是:

  1. 这是触发页面加载时JavaScript事件的最佳方法吗?还是有更好/更新的方法?
  2. 如果这是触发页面加载上事件的唯一方法,那么如何确保由不同脚本运行的多个事件能够顺利执行?
7个回答

46

window.onload = function(){};可以运行,但你可能已经注意到,它只允许你指定一个监听器

我认为更好/更新的方法是使用框架,或者仅使用本地addEventListenerattachEvent(为IE)方法的简单实现,这样还可以删除事件的监听器。

以下是跨浏览器的实现:

// Cross-browser implementation of element.addEventListener()
function listen(evnt, elem, func) {
    if (elem.addEventListener)  // W3C DOM
        elem.addEventListener(evnt,func,false);
    else if (elem.attachEvent) { // IE DOM
         var r = elem.attachEvent("on"+evnt, func);
         return r;
    }
    else window.alert('I\'m sorry Dave, I\'m afraid I can\'t do that.');
}

// Use: listen("event name", elem, func);

对于window.onload情况,请使用:listen("load", window, function() { });


编辑 我想通过添加其他人指出的宝贵信息来扩展我的答案。

这涉及到DOMContentLoaded(Mozilla,Opera和webkit夜间版目前支持此)和onreadystatechange(用于IE)事件,可以应用于document对象以了解何时可以操纵文档(而无需等待所有图像/样式表等加载)。

有很多“hacky”实现来跨浏览器支持这一点,因此我强烈建议使用框架来实现此功能。


2
我想强烈推荐jQuery的.ready()函数:http://api.jquery.com/ready/ - James McCormack
2
+1 表示“仅限一个监听器”,这正是我现在所需要的提示! - brabec
1
我喜欢警告信息:D - Aamir Afridi

13

在多次创建时,window.onload 事件会被覆盖。要追加函数,请使用 window.addEventListener(W3C标准)或 window.attachEvent(适用于IE)。使用以下代码可以运行。

if (window.addEventListener) // W3C standard
{
  window.addEventListener('load', myFunction, false); // NB **not** 'onload'
} 
else if (window.attachEvent) // Microsoft
{
  window.attachEvent('onload', myFunction);
}

10
现代JavaScript框架引入了“文档就绪”事件的概念。这是一个在文档准备好进行DOM操作时触发的事件。“onload”事件仅在页面上的所有内容都加载完成后才触发。
除了“文档就绪”事件外,这些框架还提供了一种方法来排队多个JavaScript代码片段和函数以在事件触发时运行。
因此,如果您反对使用框架,则最好实现自己的document.onload队列。
如果您不反对使用框架,则需要查看jQuery和document.ready, Prototype和dom:loaded, Dojo和addOnLoad或Google [您的框架]和“文档就绪”。
如果您尚未选择框架但有兴趣,jQuery是一个很好的起点。它不会改变JavaScript的核心功能,并且通常会让您随心所欲地做事情。

有没有关于onload队列实现的好参考资料,或者更多解释文档准备就绪和onload事件之间的区别? - netpoetica
我不想卷入内容争议,但像jQuery这样的库确实不是框架。请参见https://dev59.com/U2w05IYBdhLWcg3wuUOZ。 - Benjamin Gruenbaum
我能看到这个问题的两面,但是从Web开发人员使用jQuery的方式来看,它更像一个框架,而不管项目本身如何描述。对我来说,这似乎是一个观点、角度和答案作者的问题——特别是因为我是在参考JavaScript和document.ready技术的更广泛世界。没有恶意或争论的意图。 - Alana Storm
当然,Stack Overflow允许您将任何想法写成答案,除此之外,答案听起来还不错。但是,事情是明确定义的,答案的那部分客观上是错误的。事实上,正如答案所描述的那样,“它不会改变JavaScript的核心功能,并且通常会让您自己决定何时以您喜欢的方式进行操作”,这正是它是库而不是框架的原因。jQuery和类似的DOM操作库不执行控制反转,它们只提供编写代码的实用工具。没有好莱坞方法 :) - Benjamin Gruenbaum

2

Joomla带有MooTools,因此您会发现使用MooTools库来编写附加代码最为方便。MooTools带有一个自定义事件domready,当页面加载和文档树解析完成时会触发该事件。

window.addEvent( domready, function() { code to execute on load here } );

关于MooTools的更多信息可以在这里找到。Joomla 1.5目前使用MT1.1,而Joomla 1.6 alpha版本将包含MT1.2。


这个答案在当时是有效的,但在新版本的Joomla中使用了JQuery。 - Elin

1
这是不太规范但更短的方式 :P
function load(){
   *code*
}

window[ addEventListener ? 'addEventListener' : 'attachEvent' ]
( addEventListener ? 'load' : 'onload', function(){} )

1
个人而言,我更喜欢this method。它不仅允许您拥有多个 onload 函数,而且如果某些脚本在您使用之前定义了它before,那么这种方法足够好以处理它... 剩下的唯一问题是,如果页面加载几个未使用 window.addLoad()函数的脚本,则是他们的问题:)。
P.S. 如果您想稍后“链接”更多函数,它也非常适用。

0

由于我总是在文档底部包含jQuery/bootstrap JS文件,并且无法访问文档中的$,因此我开发了一个微小的“init”插件,这是我在页面顶部包含的唯一JS脚本:

window.init = new function() {
    var list = [];

    this.push = function(callback) {
        if (typeof window.jQuery !== "undefined") {
            callback();
        } else {
            list.push(callback);
        }
    };

    this.run = function() {

        if (typeof window.jQuery !== "undefined") {
            for(var i in list) {
                try {
                    list[i]();
                } catch (ex) {
                    console.error(ex);
                }
            }
            list = [];
        }
    };

    if (window.addEventListener) {
        window.addEventListener("load", this.run, false);
    } else if (window.attachEvent) {
        window.attachEvent("onload", this.run);
    } else {
        if (window.onload && window.onload !== this.run) {
            this.push(window.onload);
        }
        window.onload = this.run;
    }
};

使用这个方法,我可以在jQuery和bootstrap引入之前定义任何匿名的页面加载器,并确保它会在jQuery存在时触发:
init.push(function() {

    $('[name="date"]').datepicker({
        endDate: '0d',
        format: 'yyyy-mm-dd',
        autoclose: true
    }).on('hide', function() {
        // $.ajax
    });

    $('[name="keyword_id"]').select2();
});

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