没有使用jQuery的$(document).ready()等效方法是什么?

2412

我有一个使用了$(document).ready的脚本,但它没有使用jQuery的其他任何功能。 我想通过去除jQuery依赖来减轻它的负担。

我如何在不使用jQuery的情况下实现自己的$(document).ready功能? 我知道使用window.onload将不同,因为window.onload会在所有图像、框架等都加载完成后触发。


302
不是完全相同的功能。 - Joel Mueller
46
正如这个答案所述,如果你只需要jQuery中的 $(document).ready,那么你可以通过在页面底部而不是顶部运行代码来轻松解决这个问题。 HTML5Boilerplate正是采用了这种方法。 - Blazemonger
5
为什么不直接使用DOMContentLoaded事件?它可以在IE9及以上版本上使用。http://caniuse.com/domcontentloaded https://developer.mozilla.org/en-US/docs/Web/Events/DOMContentLoaded - Brock
值得一看:https://developer.mozilla.org/zh-CN/docs/Web/API/Document/readyState - Andrew
https://developer.mozilla.org/en-US/docs/Web/API/Document/DOMContentLoaded_event - Kithraya
我认为一个有趣的答案是解析jQuery是如何做到这一点的? - Chris Pink
39个回答

15

跨浏览器(包括旧版浏览器)且简单的解决方案:

var docLoaded = setInterval(function () {
    if(document.readyState !== "complete") return;
    clearInterval(docLoaded);

    /*
        Your code goes here i.e. init()
    */
}, 30);

在 jsfiddle 中显示警告


13

最近我在为一个移动网站使用这段代码。这是约翰·雷西格从《Pro JavaScript Techniques》中简化的版本。它依赖于addEvent。

var ready = ( function () {
  function ready( f ) {
    if( ready.done ) return f();

    if( ready.timer ) {
      ready.ready.push(f);
    } else {
      addEvent( window, "load", isDOMReady );
      ready.ready = [ f ];
      ready.timer = setInterval(isDOMReady, 13);
    }
  };

  function isDOMReady() {
    if( ready.done ) return false;

    if( document && document.getElementsByTagName && document.getElementById && document.body ) {
      clearInterval( ready.timer );
      ready.timer = null;
      for( var i = 0; i < ready.ready.length; i++ ) {
        ready.ready[i]();
      }
      ready.ready = null;
      ready.done = true;
    }
  }

  return ready;
})();

14
请注意此代码,它并不等同于 $(document).ready。此代码在 document.body 准备就绪时触发回调函数,但这并不保证 DOM 已经完全加载。 - Karolis

11

jQuery的答案对我非常有用。稍加修改后,它可以很好地满足我的需求。 希望它能对其他人有所帮助。

function onReady ( callback ){
    var addListener = document.addEventListener || document.attachEvent,
        removeListener =  document.removeEventListener || document.detachEvent
        eventName = document.addEventListener ? "DOMContentLoaded" : "onreadystatechange"

    addListener.call(document, eventName, function(){
        removeListener( eventName, arguments.callee, false )
        callback()
    }, false )
}

1
在某些浏览器上,removeListener 需要使用 document 作为上下文进行调用,例如 removeListener.call(document, ... - Ron

10

这是一个能够在所有浏览器中工作(包括 IE 8)的用来测试DOM是否准备就绪的最小代码片段:

r(function(){
    alert('DOM Ready!');
});
function r(f){/in/.test(document.readyState)?setTimeout('r('+f+')',9):f()}

请查看此答案


8
只需将以下内容添加到您的 HTML 页面底部即可...
<script>
    Your_Function();
</script>

因为HTML文档是自上而下解析的。

7

使用纯JavaScript的最简单方法。不需要jQuery:

document.addEventListener("DOMContentLoaded", function(event) {
   // Your code to run since DOM is loaded and ready
});

7

最简单实用的方法

我从 PlainJS 中选择了一个答案,对我来说它很好用。 它扩展了 DOMContentLoaded 以便于在所有浏览器中都可以接受。


此函数相当于jQuery的 $(document).ready() 方法:

document.addEventListener('DOMContentLoaded', function(){
    // do something
});

然而,与jQuery相比,这段代码只能在现代浏览器中(IE > 8)正确运行,在文档在插入此脚本时已经被渲染的情况下(例如通过Ajax),它将无法正常工作。因此,我们需要稍微进行扩展:

function run() {
    // do something
}

// in case the document is already rendered
if (document.readyState!='loading') run();
// modern browsers
else if (document.addEventListener) 
document.addEventListener('DOMContentLoaded', run);
// IE <= 8
else document.attachEvent('onreadystatechange', function(){
    if (document.readyState=='complete') run();
});

这基本上涵盖了所有可能性,并且是jQuery助手的可行替代品。

6

值得一看的是 Rock Solid addEvent()http://www.braksator.com/how-to-make-your-own-jquery

以下是代码,以防该网站失效。

function addEvent(obj, type, fn) {
    if (obj.addEventListener) {
        obj.addEventListener(type, fn, false);
        EventCache.add(obj, type, fn);
    }
    else if (obj.attachEvent) {
        obj["e"+type+fn] = fn;
        obj[type+fn] = function() { obj["e"+type+fn]( window.event ); }
        obj.attachEvent( "on"+type, obj[type+fn] );
        EventCache.add(obj, type, fn);
    }
    else {
        obj["on"+type] = obj["e"+type+fn];
    }
}

var EventCache = function(){
    var listEvents = [];
    return {
        listEvents : listEvents,
        add : function(node, sEventName, fHandler){
            listEvents.push(arguments);
        },
        flush : function(){
            var i, item;
            for(i = listEvents.length - 1; i >= 0; i = i - 1){
                item = listEvents[i];
                if(item[0].removeEventListener){
                    item[0].removeEventListener(item[1], item[2], item[3]);
                };
                if(item[1].substring(0, 2) != "on"){
                    item[1] = "on" + item[1];
                };
                if(item[0].detachEvent){
                    item[0].detachEvent(item[1], item[2]);
                };
                item[0][item[1]] = null;
            };
        }
    };
}();

// Usage
addEvent(window, 'unload', EventCache.flush);
addEvent(window, 'load', function(){alert("I'm ready");});

第二个链接已经失效。 - Peter Mortensen
https://web.archive.org/web/20091229112223/http://www.braksator.com/how-to-make-your-own-jquery - jkdev

5

与jQuery相比,使用JavaScript等价代码总是更好的选择。一个原因是减少依赖库的数量,并且它们比jQuery等价代码更快。

关于jQuery等价代码的一个绝妙参考是http://youmightnotneedjquery.com/

至于你的问题,我从上面的链接中采用了以下代码 :) 唯一的注意事项是它只适用于Internet Explorer 9及更高版本。

function ready(fn) {
    if (document.readyState != 'loading') {
        fn();
    }
    else {
        document.addEventListener('DOMContentLoaded', fn);
    }
}

4
这个跨浏览器的代码会在DOM准备就绪后调用一个函数:
var domReady=function(func){
    var scriptText='('+func+')();';
    var scriptElement=document.createElement('script');
    scriptElement.innerText=scriptText;
    document.body.appendChild(scriptElement);
};

这是它的工作原理:
  1. domReady 的第一行调用函数的 toString 方法,以获取您传递的函数的字符串表示形式,并将其包装在立即调用该函数的表达式中。
  2. domReady 的其余部分创建一个带有该表达式的脚本元素,并将其附加到文档的 body 中。
  3. 浏览器在 DOM 准备就绪后运行附加到 body 的脚本标记。
例如,如果您执行以下操作:domReady(function(){alert();});,则以下内容将附加到 body 元素:
 <script>(function (){alert();})();</script>

请注意,这仅适用于用户定义的函数。以下内容不起作用:domReady(alert);

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