2267

我有一个使用 的脚本$(document).ready,但它不使用 jQuery 中的任何其他内容。我想通过删除 jQuery 依赖项来减轻它。

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

4

39 回答 39

1702

有一个基于标准的替换,DOMContentLoaded超过99% 的浏览器都支持,但 IE8 不支持:

document.addEventListener("DOMContentLoaded", function(event) { 
  //do work
});

jQuery 的原生函数比 window.onload 复杂得多,如下图所示。

function bindReady(){
    if ( readyBound ) return;
    readyBound = true;

    // Mozilla, Opera and webkit nightlies currently support this event
    if ( document.addEventListener ) {
        // Use the handy event callback
        document.addEventListener( "DOMContentLoaded", function(){
            document.removeEventListener( "DOMContentLoaded", arguments.callee, false );
            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", function(){
            if ( document.readyState === "complete" ) {
                document.detachEvent( "onreadystatechange", arguments.callee );
                jQuery.ready();
            }
        });

        // If IE and not an iframe
        // continually check to see if the document is ready
        if ( document.documentElement.doScroll && window == window.top ) (function(){
            if ( jQuery.isReady ) return;

            try {
                // If IE is used, use the trick by Diego Perini
                // http://javascript.nwbox.com/IEContentLoaded/
                document.documentElement.doScroll("left");
            } catch( error ) {
                setTimeout( arguments.callee, 0 );
                return;
            }

            // and execute any waiting functions
            jQuery.ready();
        })();
    }

    // A fallback to window.onload, that will always work
    jQuery.event.add( window, "load", jQuery.ready );
}
于 2009-04-28T21:59:53.337 回答
368

编辑:

这是 jQuery 就绪的可行替代品

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

ready(function(){
    // do something
});

取自 https://plainjs.com/javascript/events/running-code-when-the-document-is-ready-15/

另一个很好的 domReady 函数取自https://stackoverflow.com/a/9899701/175071


由于接受的答案远未完成,我将jQuery.ready()基于 jQuery 1.6.2 源代码的“就绪”函数拼接在一起:

var ready = (function(){

    var readyList,
        DOMContentLoaded,
        class2type = {};
        class2type["[object Boolean]"] = "boolean";
        class2type["[object Number]"] = "number";
        class2type["[object String]"] = "string";
        class2type["[object Function]"] = "function";
        class2type["[object Array]"] = "array";
        class2type["[object Date]"] = "date";
        class2type["[object RegExp]"] = "regexp";
        class2type["[object Object]"] = "object";

    var ReadyObj = {
        // Is the DOM ready to be used? Set to true once it occurs.
        isReady: false,
        // A counter to track how many items to wait for before
        // the ready event fires. See #6781
        readyWait: 1,
        // Hold (or release) the ready event
        holdReady: function( hold ) {
            if ( hold ) {
                ReadyObj.readyWait++;
            } else {
                ReadyObj.ready( true );
            }
        },
        // Handle when the DOM is ready
        ready: function( wait ) {
            // Either a released hold or an DOMready/load event and not yet ready
            if ( (wait === true && !--ReadyObj.readyWait) || (wait !== true && !ReadyObj.isReady) ) {
                // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
                if ( !document.body ) {
                    return setTimeout( ReadyObj.ready, 1 );
                }

                // Remember that the DOM is ready
                ReadyObj.isReady = true;
                // If a normal DOM Ready event fired, decrement, and wait if need be
                if ( wait !== true && --ReadyObj.readyWait > 0 ) {
                    return;
                }
                // If there are functions bound, to execute
                readyList.resolveWith( document, [ ReadyObj ] );

                // Trigger any bound ready events
                //if ( ReadyObj.fn.trigger ) {
                //    ReadyObj( document ).trigger( "ready" ).unbind( "ready" );
                //}
            }
        },
        bindReady: function() {
            if ( readyList ) {
                return;
            }
            readyList = ReadyObj._Deferred();

            // Catch cases where $(document).ready() is called after the
            // browser event has already occurred.
            if ( document.readyState === "complete" ) {
                // Handle it asynchronously to allow scripts the opportunity to delay ready
                return setTimeout( ReadyObj.ready, 1 );
            }

            // 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", ReadyObj.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", ReadyObj.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();
                }
            }
        },
        _Deferred: function() {
            var // callbacks list
                callbacks = [],
                // stored [ context , args ]
                fired,
                // to avoid firing when already doing so
                firing,
                // flag to know if the deferred has been cancelled
                cancelled,
                // the deferred itself
                deferred  = {

                    // done( f1, f2, ...)
                    done: function() {
                        if ( !cancelled ) {
                            var args = arguments,
                                i,
                                length,
                                elem,
                                type,
                                _fired;
                            if ( fired ) {
                                _fired = fired;
                                fired = 0;
                            }
                            for ( i = 0, length = args.length; i < length; i++ ) {
                                elem = args[ i ];
                                type = ReadyObj.type( elem );
                                if ( type === "array" ) {
                                    deferred.done.apply( deferred, elem );
                                } else if ( type === "function" ) {
                                    callbacks.push( elem );
                                }
                            }
                            if ( _fired ) {
                                deferred.resolveWith( _fired[ 0 ], _fired[ 1 ] );
                            }
                        }
                        return this;
                    },

                    // resolve with given context and args
                    resolveWith: function( context, args ) {
                        if ( !cancelled && !fired && !firing ) {
                            // make sure args are available (#8421)
                            args = args || [];
                            firing = 1;
                            try {
                                while( callbacks[ 0 ] ) {
                                    callbacks.shift().apply( context, args );//shifts a callback, and applies it to document
                                }
                            }
                            finally {
                                fired = [ context, args ];
                                firing = 0;
                            }
                        }
                        return this;
                    },

                    // resolve with this as context and given arguments
                    resolve: function() {
                        deferred.resolveWith( this, arguments );
                        return this;
                    },

                    // Has this deferred been resolved?
                    isResolved: function() {
                        return !!( firing || fired );
                    },

                    // Cancel
                    cancel: function() {
                        cancelled = 1;
                        callbacks = [];
                        return this;
                    }
                };

            return deferred;
        },
        type: function( obj ) {
            return obj == null ?
                String( obj ) :
                class2type[ Object.prototype.toString.call(obj) ] || "object";
        }
    }
    // The DOM ready check for Internet Explorer
    function doScrollCheck() {
        if ( ReadyObj.isReady ) {
            return;
        }

        try {
            // If IE is used, use the trick by Diego Perini
            // http://javascript.nwbox.com/IEContentLoaded/
            document.documentElement.doScroll("left");
        } catch(e) {
            setTimeout( doScrollCheck, 1 );
            return;
        }

        // and execute any waiting functions
        ReadyObj.ready();
    }
    // Cleanup functions for the document ready method
    if ( document.addEventListener ) {
        DOMContentLoaded = function() {
            document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false );
            ReadyObj.ready();
        };

    } else if ( document.attachEvent ) {
        DOMContentLoaded = function() {
            // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
            if ( document.readyState === "complete" ) {
                document.detachEvent( "onreadystatechange", DOMContentLoaded );
                ReadyObj.ready();
            }
        };
    }
    function ready( fn ) {
        // Attach the listeners
        ReadyObj.bindReady();

        var type = ReadyObj.type( fn );

        // Add the callback
        readyList.done( fn );//readyList is result of _Deferred()
    }
    return ready;
})();

如何使用:

<script>
    ready(function(){
        alert('It works!');
    });
    ready(function(){
        alert('Also works!');
    });
</script>

我不确定这段代码的功能如何,但它在我的表面测试中运行良好。这花了相当长的时间,所以我希望你和其他人可以从中受益。

PS.:我建议编译它。

或者您可以使用http://dustindiaz.com/smallest-domready-ever

function r(f){/in/.test(document.readyState)?setTimeout(r,9,f):f()}
r(function(){/*code to run*/});

或者原生函数,如果你只需要支持新的浏览器(与 jQuery 不同,如果你在页面加载后添加它,这将不会运行)

document.addEventListener('DOMContentLoaded',function(){/*fun code to run*/})
于 2011-08-13T20:52:06.120 回答
216

三个选项:

  1. 如果script是正文的最后一个标签,则 DOM 将在脚本标签执行之前准备好
  2. 当 DOM 准备就绪时,“readyState”将变为“完成”
  3. 将所有内容放在“DOMContentLoaded”事件侦听器下

onreadystatechange

  document.onreadystatechange = function () {
     if (document.readyState == "complete") {
     // document is ready. Do your stuff here
   }
 }

来源:MDN

DOMContentLoaded

document.addEventListener('DOMContentLoaded', function() {
   console.log('document is ready. I can sleep now');
});

关注石器时代浏览器: 前往jQuery源码并使用该ready功能。在这种情况下,您不会解析+执行整个库,而您正在做的只是其中的一小部分。

于 2013-09-12T22:33:04.597 回答
93

把你的<script>/*JavaScript code*/</script>权利放在结束 </body>标签之前。

诚然,这可能不适合每个人的目的,因为它需要更改 HTML 文件,而不仅仅是在 JavaScript 文件中做一些事情document.ready,但仍然......

于 2009-12-07T16:46:49.640 回答
69

穷人的解决方法:

var checkLoad = function() {   
    document.readyState !== "complete" ? setTimeout(checkLoad, 11) : alert("loaded!");   
};  

checkLoad();  

查看小提琴

添加了这个,我猜更好一点,自己的范围,并且非递归

(function(){
    var tId = setInterval(function() {
        if (document.readyState == "complete") onComplete()
    }, 11);
    function onComplete(){
        clearInterval(tId);    
        alert("loaded!");    
    };
})()

查看小提琴

于 2012-08-04T18:13:42.553 回答
39

我用这个:

document.addEventListener("DOMContentLoaded", function(event) { 
    //Do work
});

注意:这可能只适用于较新的浏览器,尤其是这些:http ://caniuse.com/#feat=domcontentloaded

于 2013-12-23T19:14:32.707 回答
22

真的,如果您只关心Internet Explorer 9+,则此代码足以替换jQuery.ready

    document.addEventListener("DOMContentLoaded", callback);

如果您担心Internet Explorer 6和一些非常奇怪和罕见的浏览器,这将起作用:

domReady: function (callback) {
    // Mozilla, Opera and WebKit
    if (document.addEventListener) {
        document.addEventListener("DOMContentLoaded", callback, false);
        // If Internet Explorer, the event model is used
    } else if (document.attachEvent) {
        document.attachEvent("onreadystatechange", function() {
            if (document.readyState === "complete" ) {
                callback();
            }
        });
        // A fallback to window.onload, that will always work
    } else {
        var oldOnload = window.onload;
        window.onload = function () {
            oldOnload && oldOnload();
            callback();
        }
    }
},
于 2014-11-07T07:45:18.243 回答
21

现在是 2020 年,<script>标签具有defer属性。

例如:

<script src="demo_defer.js" defer></script>

它指定当页面完成解析时执行脚本。

https://www.w3schools.com/tags/att_script_defer.asp

于 2020-01-23T22:30:11.413 回答
20

这个问题很久以前就被问过了。对于刚刚看到这个问题的任何人,现在有一个名为“您可能不需要 jquery”的站点 ,它分解了 - 按所需的 IE 支持级别 - jquery 的所有功能,并提供了一些替代的、更小的库。

根据您的 IE8 文档准备脚本可能不需要 jquery

function ready(fn) {
    if (document.readyState != 'loading')
        fn();
    else if (document.addEventListener)
        document.addEventListener('DOMContentLoaded', fn);
    else
        document.attachEvent('onreadystatechange', function() {
            if (document.readyState != 'loading')
                fn();
        });
}
于 2015-02-16T14:15:41.920 回答
13

我最近将其用于移动网站。这是 John Resig 的“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;
})();
于 2010-09-22T01:29:38.827 回答
12

跨浏览器(旧浏览器也是)和一个简单的解决方案:

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

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

在 jsfiddle 中显示警报

于 2013-11-18T21:58:51.913 回答
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 )
}
于 2012-09-05T16:56:58.027 回答
9

这是测试 DOM 就绪的最小代码片段,它适用于所有浏览器(甚至 IE 8):

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

看到这个答案

于 2015-05-22T06:20:16.767 回答
8

只需将其添加到 HTML 页面的底部...

<script>
    Your_Function();
</script>

因为,HTML 文档是由 top-bottom 解析的。

于 2013-02-23T11:51:26.570 回答
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");});
于 2011-09-28T11:13:41.863 回答
5

最小和 100% 工作

我从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 助手的可行替代品。

于 2019-09-30T06:41:57.457 回答
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. body浏览器在 DOM 准备好后运行附加的脚本标签。

例如,如果您这样做: domReady(function(){alert();});,则以下内容将附加到body元素:

 <script>(function (){alert();})();</script>

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

于 2014-12-27T16:52:42.120 回答
4

与 jQuery 相比,使用 JavaScript 等价物总是好的。一个原因是依赖的库少了一个,而且它们比 jQuery 等价物快得多。

jQuery 等价物的一个很好的参考是http://youmightnotneedjquery.com/

就您的问题而言,我从上面的链接中获取了以下代码 :) 唯一需要注意的是它仅适用于Internet Explorer 9及更高版本。

function ready(fn) {
    if (document.readyState != 'loading') {
        fn();
    }
    else {
        document.addEventListener('DOMContentLoaded', fn);
    }
}
于 2016-02-26T18:38:27.187 回答
3

这个解决方案怎么样?

// other onload attached earlier
window.onload=function() {
   alert('test');
};

tmpPreviousFunction=window.onload ? window.onload : null;

// our onload function
window.onload=function() {
   alert('another message');

   // execute previous one
   if (tmpPreviousFunction) tmpPreviousFunction();
};
于 2012-08-17T07:33:55.160 回答
3

我们发现了我们的一个快速而简单的跨浏览器实现,它可以用最少的实现来解决大多数简单的情况:

window.onReady = function onReady(fn){
    document.body ? fn() : setTimeout(function(){ onReady(fn);},50);
};
于 2014-07-29T13:08:04.533 回答
3

比较

这里(在下面的片段中)是选择的可用浏览器“内置”方法及其执行顺序的比较。评论

  • 任何现代document.onload浏览器都不支持 (X) (从不触发事件)
  • 如果您<body onload="bodyOnLoad()">同时使用 (F) 和window.onload(E),那么只会执行第一个(因为它会覆盖第二个)
  • (F) 中给出的事件处理程序<body onload="...">由附加onload函数包装
  • document.onreadystatechange(D) 不覆盖document .addEventListener('readystatechange'...)(C) 可能 cecasueonXYZevent-like方法独立于addEventListener队列(允许添加多个侦听器)。执行这两个处理程序之间可能没有任何反应。
  • 所有脚本都在控制台中写入其时间戳 - 但也div可以在正文中写入其时间戳的脚本(在脚本执行后单击“整页”链接以查看它)。
  • 解决方案readystatechange(C,D)由浏览器多次执行,但针对不同的文档状态:
  • loading - 文档正在加载(没有在代码段中触发)
  • 交互式- 文档被解析,之前触发DOMContentLoaded
  • 完成- 文档和资源已加载,之前触发body/window onload

<html>

<head>
  <script>
    // solution A
    console.log(`[timestamp: ${Date.now()}] A: Head script`) ;
    
    // solution B
    document.addEventListener("DOMContentLoaded", () => {
      print(`[timestamp: ${Date.now()}] B: DOMContentLoaded`);
    });

    // solution C
    document.addEventListener('readystatechange', () => {
      print(`[timestamp: ${Date.now()}] C: ReadyState: ${document.readyState}`);
    });
   
    // solution D
    document.onreadystatechange = s=> {print(`[timestamp: ${Date.now()}] D: document.onreadystatechange ReadyState: ${document.readyState}`)};
    
    // solution E (never executed)
    window.onload = () => {
      print(`E: <body onload="..."> override this handler`);
    };

    // solution F
    function bodyOnLoad() {
      print(`[timestamp: ${Date.now()}] F: <body onload='...'>`);      
      infoAboutOnLoad(); // additional info
    }
    
    // solution X
    document.onload = () => {print(`document.onload is never fired`)};



    // HELPERS

    function print(txt) { 
      console.log(txt);
      if(mydiv) mydiv.innerHTML += txt.replace('<','&lt;').replace('>','&gt;') + '<br>';
    }
    
    function infoAboutOnLoad() {
      console.log("window.onload (after  override):", (''+document.body.onload).replace(/\s+/g,' '));
      console.log(`body.onload==window.onload --> ${document.body.onload==window.onload}`);
    }
            
    console.log("window.onload (before override):", (''+document.body.onload).replace(/\s+/g,' '));

  </script>
</head>

<body onload="bodyOnLoad()">
  <div id="mydiv"></div>

  <!-- this script must te at the bottom of <body> -->
  <script>
    // solution G
    print(`[timestamp: ${Date.now()}] G: <body> bottom script`);
  </script>
</body>

</html>

于 2020-08-20T20:38:17.610 回答
3

2022版

在 2022 年,你需要做的就是把 defer 属性放在你的脚本上,然后加载到 head 中!

参考:https ://developer.mozilla.org/en-US/docs/Web/HTML/Element/script#attr-defer

<!doctype html>
<html>
<head>
  <script src="/script.js" defer></script>
</head>
<body>

 </p>In 2022, all you need to do is put the defer attribute on your script, and load it in the head!</p>

</body>
</html>
于 2021-12-16T20:39:29.940 回答
2

如果您不必支持非常旧的浏览器,即使您的外部脚本加载了异步属性,也可以使用以下方法:

HTMLDocument.prototype.ready = new Promise(function(resolve) {
   if(document.readyState != "loading")
      resolve();
   else
      document.addEventListener("DOMContentLoaded", function() {
         resolve();
      });
});

document.ready.then(function() {
   console.log("document.ready");
});
于 2017-10-22T05:59:46.387 回答
2

我只是使用:

setTimeout(function(){
    //reference/manipulate DOM here
});

document.addEventListener("DOMContentLoaded" //etc最上面的答案不同,它可以追溯到 IE9 - http://caniuse.com/#search=DOMContentLoaded仅表示最近到 IE11。

setTimeout有趣的是,我在 2009 年偶然发现了这个解决方案:检查 DOM 的准备情况是否矫枉过正?,这可能措辞稍微好一点,因为我的意思是“使用各种框架的更复杂的方法来检查 DOM 的准备情况是否有点过头了”。

对于这种技术为什么有效,我最好的解释是,当到达具有这种 setTimeout 的脚本时,DOM 正在被解析,因此 setTimeout 内的代码的执行被推迟到该操作完成。

于 2017-10-25T01:42:59.730 回答
1

此处介绍的 setTimeout/setInterval 解决方案仅适用于特定情况。

该问题尤其出现在不超过 8 的旧 Internet Explorer 版本中。

影响这些 setTimeout/setInterval 解决方案成功的变量是:

1) dynamic or static HTML
2) cached or non cached requests
3) size of the complete HTML document
4) chunked or non chunked transfer encoding

解决此特定问题的原始(本机 Javascript)代码在这里:

https://github.com/dperini/ContentLoaded
http://javascript.nwbox.com/ContentLoaded (test)

这是 jQuery 团队构建实现的代码。

于 2014-08-05T11:04:29.297 回答
1

对于 IE9+:

function ready(fn) {
  if (document.readyState != 'loading'){
    fn();
  } else {
    document.addEventListener('DOMContentLoaded', fn);
  }
}
于 2016-02-03T15:20:32.487 回答
1

这是我使用的,它速度快,涵盖了我认为的所有基础;适用于除 IE<9 之外的所有内容。

(() => { function fn() {
    // "On document ready" commands:
    console.log(document.readyState);
};  
  if (document.readyState != 'loading') {fn()}
  else {document.addEventListener('DOMContentLoaded', fn)}
})();

这似乎涵盖了所有情况:

  • 如果 DOM 已经准备好,则立即触发(如果 DOM 不是“正在加载”,而是“交互式”或“完成”)
  • 如果 DOM 仍在加载,它会为 DOM 可用(交互式)设置一个事件侦听器。

DOMContentLoaded 事件在 IE9 和其他所有东西中都可用,所以我个人认为使用它是可以的。如果您没有将代码从 ES2015 转换为 ES5,请将箭头函数声明重写为常规匿名函数。

如果您想等到所有资产都加载完毕,显示所有图像等,然后使用 window.onload 代替。

于 2016-07-07T13:46:43.443 回答
1

现在你应该使用模块。将您的代码放入模块的默认函数中,然后将该函数导入脚本元素中。

client.js

export default function ()
{
  alert ("test");
}

index.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>test</title>
  </head>
  <body>
    <script type="module">
      import main from './client.js';
      main ();
    </script>
  </body>
</html>
于 2020-11-21T17:57:13.417 回答
0

如果您在 BODY 底部附近加载 jQuery,但在写出 jQuery(<func>) 或 jQuery(document).ready(<func>) 的代码时遇到问题,请查看Github 上的jqShim

它不是重新创建自己的文档就绪函数,而是简单地保留这些函数,直到 jQuery 可用,然后按预期继续使用 jQuery。将 jQuery 移到 body 底部的目的是加快页面加载速度,您仍然可以通过在模板头部内联 jqShim.min.js 来完成它。

我最终编写了这段代码来将WordPress中的所有脚本移动到页脚,而现在只有这个 shim 代码直接位于页眉中。

于 2014-02-21T17:16:59.003 回答
0
(function(f){
  if(document.readyState != "loading") f();
  else document.addEventListener("DOMContentLoaded", f);
})(function(){
  console.log("The Document is ready");
});
于 2018-11-27T21:40:42.223 回答
0

大多数 vanilla JS Ready 函数不考虑在 文档已经加载DOMContentLoaded设置处理程序的场景 - 这意味着该函数将永远不会运行。如果您在外部脚本 ( ) 中查找,就会发生这种情况。DOMContentLoadedasync<script async src="file.js"></script>

下面的代码DOMContentLoaded仅在文档readyState不是interactive或时检查complete

var DOMReady = function(callback) {
  document.readyState === "interactive" || document.readyState === "complete" ? callback() : document.addEventListener("DOMContentLoaded", callback());
};
DOMReady(function() {
  //DOM ready!
});

如果你也想支持 IE:

var DOMReady = function(callback) {
    if (document.readyState === "interactive" || document.readyState === "complete") {
        callback();
    } else if (document.addEventListener) {
        document.addEventListener('DOMContentLoaded', callback());
    } else if (document.attachEvent) {
        document.attachEvent('onreadystatechange', function() {
            if (document.readyState != 'loading') {
                callback();
            }
        });
    }
};

DOMReady(function() {
  // DOM ready!
});
于 2019-04-12T10:32:41.637 回答
0

适用于所有已知的浏览器(通过 BrowserStack 测试)。IE6+、Safari 1+、Chrome 1+、Opera 等。使用DOMContentLoaded, 回退到document.documentElement.doScroll()window.onload.

/*! https://github.com/Kithraya/DOMContentLoaded v1.2.6 | MIT License */

DOMContentLoaded.version = "1.2.6";

function DOMContentLoaded() { "use strict";
    
    var ael = 'addEventListener', rel = 'removeEventListener', aev = 'attachEvent', dev = 'detachEvent';
    var alreadyRun = false, // for use in the idempotent function ready()
        funcs = arguments;
    
    // old versions of JS return '[object Object]' for null.
    function type(obj) { return (obj === null) ? 'null' : Object.prototype.toString.call(obj).slice(8,-1).toLowerCase() }
    function microtime() { return + new Date() } 
    
     /* document.readyState === 'complete' reports correctly in every browser I have tested, including IE.
        But IE6 to 10 don't return the correct readyState values as per the spec:
        readyState is sometimes 'interactive', even when the DOM isn't accessible in IE6/7 so checking for the onreadystatechange event like jQuery does is not optimal
        readyState is complete at basically the same time as 'window.onload' (they're functionally equivalent, within a few tenths of a second)
        Accessing undefined properties of a defined object (document) will not throw an error (in case readyState is undefined).
     */
    
    // Check for IE < 11 via conditional compilation
    /// values: 5?: IE5, 5.5?: IE5.5, 5.6/5.7: IE6/7, 5.8: IE8, 9: IE9, 10: IE10, 11*: (IE11 older doc mode), undefined: IE11 / NOT IE
    var jscript_version = Number( new Function("/*@cc_on return @_jscript_version; @*\/")() ) || NaN;
    
    // check if the DOM has already loaded
    if (document.readyState === 'complete') { ready(null); return; }  // here we send null as the readyTime, since we don't know when the DOM became ready.
    
    if (jscript_version < 9) { doIEScrollCheck(); return; } // For IE<9 poll document.documentElement.doScroll(), no further actions are needed.
    
     /* 
        Chrome, Edge, Firefox, IE9+, Opera 9+, Safari 3.1+, Android Webview, Chrome for Android, Edge Mobile, 
        Firefox for Android 4+, Opera for Android, iOS Safari, Samsung Internet, etc, support addEventListener
        And IE9+ supports 'DOMContentLoaded' 
     */
        
    if (document[ael]) {
        document[ael]("DOMContentLoaded", ready, false); 
        window[ael]("load", ready, false); // fallback to the load event in case addEventListener is supported, but not DOMContentLoaded
    } else 
    if (aev in window) { window[aev]('onload', ready);
        /* Old Opera has a default of window.attachEvent being falsy, so we use the in operator instead
           https://dev.opera.com/blog/window-event-attachevent-detachevent-script-onreadystatechange/

           Honestly if somebody is using a browser so outdated AND obscure (like Opera 7 where neither addEventListener 
           nor "DOMContLoaded" is supported, they deserve to wait for the full page).
           I CBA testing whether readyState === 'interactive' is truly interactive in browsers designed in 2003. I just assume it isn't (like in IE6-8). 
        */
    } else { // fallback to queue window.onload that will always work
       addOnload(ready);
    }
    
    
    // This function allows us to preserve any original window.onload handlers (in super old browsers where this is even necessary), 
    // while keeping the option to chain onloads, and dequeue them.
    
    function addOnload(fn) { var prev = window.onload; // old window.onload, which could be set by this function, or elsewhere
        
        // we add a function queue list to allow for dequeueing 
        // addOnload.queue is the queue of functions that we will run when when the DOM is ready
        if ( type( addOnload.queue ) !== 'array') { addOnload.queue = [];
            if ( type(prev) === 'function') { addOnload.queue.push( prev ); } // add the previously defined event handler
        }
        
        if (typeof fn === 'function') { addOnload.queue.push(fn) }

        window.onload = function() { // iterate through the queued functions
            for (var i = 0; i < addOnload.queue.length; i++) { addOnload.queue[i]() } 
        };
    }   

    // remove a queued window.onload function from the chain (simplified); 
    
    function dequeueOnload(fn) { var q = addOnload.queue, i = 0;
    
        // sort through the queued functions in addOnload.queue until we find `fn`
        if (type( q ) === 'array') {        // if found, remove from the queue
            for (; i < q.length; i++) { ;;(fn === q[i]) ? q.splice(i, 1) : 0; } // void( (fn === q[i]) ? q.splice(i, 1) : 0 ) 
        }
    }
    
    function ready(ev) { // idempotent event handler function
        if (alreadyRun) {return} alreadyRun = true; 
        
        // this time is when the DOM has loaded (or if all else fails, when it was actually possible to inference the DOM has loaded via a 'load' event)
        // perhaps this should be `null` if we have to inference readyTime via a 'load' event, but this functionality is better.
        var readyTime = microtime(); 
        
        detach(); // detach any event handlers
                        
        // run the functions
        for (var i=0; i < funcs.length; i++) {  var func = funcs[i];
            
            if (type(func) === 'function') {
                func.call(document, { 'readyTime': (ev === null ? null : readyTime), 'funcExecuteTime': microtime() }, func); 
                // jquery calls 'ready' with `this` being set to document, so we'll do the same. 
            }       
        }
    }

    function detach() {
        if (document[rel]) { 
            document[rel]("DOMContentLoaded", ready); window[rel]("load", ready);
        } else
        if (dev in window) { window[dev]("onload", ready); } 
        else {
            dequeueOnload(ready);
        }                                                               
    }
    
    function doIEScrollCheck() { // for use in IE < 9 only.
        if ( window.frameElement ) { 
            // we're in an <iframe> or similar
            // the document.documentElemeent.doScroll technique does not work if we're not at the top-level (parent document)

            try { window.attachEvent("onload", ready); } catch (e) { } // attach to onload if were in an <iframe> in IE as there's no way to tell otherwise
            
            return;
        } 
        try {
            document.documentElement.doScroll('left');  // when this statement no longer throws, the DOM is accessible in old IE
        } catch(error) {
            setTimeout(function() {
                (document.readyState === 'complete') ? ready() : doIEScrollCheck();
            }, 50);
            return;
        }
        ready();
    }
}

用法:

<script>
DOMContentLoaded(function(e) { console.log(e) });
</script>
于 2020-09-03T15:14:18.243 回答
0

使用纯 JavaScript 的最简单方法。没有 jQuery:

document.addEventListener("DOMContentLoaded", function(event) {
   // Your code to run since DOM is loaded and ready
});
于 2022-01-01T04:18:52.713 回答
-1

这是一个很好的https://stackoverflow.com/a/11810957/185565穷人的解决方案。有一条评论认为是在紧急情况下采取救助措施。这是我的修改。

function doTheMagic(counter) {
  alert("It worked on " + counter);
}

// wait for document ready then call handler function
var checkLoad = function(counter) {
  counter++;
  if (document.readyState != "complete" && counter<1000) {
    var fn = function() { checkLoad(counter); };
    setTimeout(fn,10);
  } else doTheMagic(counter);
};
checkLoad(0);
于 2013-10-03T09:12:53.440 回答
-1

@duskwuff 的编辑也支持Internet Explorer 8。不同之处在于对正则表达式的函数测试和带有匿名函数的 setTimeout 的新调用。

另外,我将超时设置为 99。

function ready(f){/in/.test(document.readyState)?setTimeout(function(){ready(f);},99):f();}
于 2014-05-27T16:22:56.600 回答
-2

试试这个:

function ready(callback){
    if(typeof callback === "function"){
        document.addEventListener("DOMContentLoaded", callback);
        window.addEventListener("load", callback);
    }else{
        throw new Error("Sorry, I can not run this!");
    }
}
ready(function(){
    console.log("It worked!");
});
于 2018-05-27T16:11:24.180 回答
-3

中的 ready 函数jQuery做了很多事情。坦率地说,除非您的网站输出非常少,否则我看不到替换它的意义。jQuery是一个非常小的库,它处理你以后需要的各种跨浏览器的东西。

反正贴在这里也没啥意义,打开jQuery看看bindReady方法。

它首先根据事件模型调用document.addEventListener("DOMContentLoaded")或调用document.attachEvent('onreadystatechange'),然后从那里继续。

于 2009-04-28T22:02:04.343 回答
-4

简而言之,我们可以使用 JavaScript 方法来代替 jQuery 中使用的 $(document).ready():

<script>
    document.addEventListener("DOMContentLoaded", function_name, false);
    function function_name(){
        statements;
    }
</script>

因此,当页面准备好时,即只有 DOMContentLoaded 时,函数 function_name() 将被调用。

于 2016-01-12T16:35:38.060 回答
-7

如果你想支持Internet Explorer 7+(没有怪癖、兼容性和其他痛苦)、最后一个Chrome、最后一个Safari、最后一个 Firefox 并且没有 iframe - 这已经足够了:

is_loaded = false
callbacks = []

loaded = ->
  is_loaded = true
  for i in [0...callbacks.length]
    callbacks[i].call document
  callbacks = []

content_loaded = ->
  document.removeEventListener "DOMContentLoaded", content_loaded, true
  loaded()

state_changed = ->
  if document.readyState is "complete"
    document.detachEvent "onreadystatechange", state_changed
    loaded()

if !!document.addEventListener
  document.addEventListener "DOMContentLoaded", content_loaded, true
else
  document.attachEvent "onreadystatechange", state_changed

dom_ready = (callback) ->
  if is_loaded
    callback.call document
  else
    callbacks.push callback
于 2013-10-27T20:55:47.123 回答