$(文档).准备等价于没有jQuery

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

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

1276659 次浏览

有一个基于标准的替换,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 eventif ( document.addEventListener ) {// Use the handy event callbackdocument.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 iframesdocument.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 readyif ( 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 functionsjQuery.ready();})();}
// A fallback to window.onload, that will always workjQuery.event.add( window, "load", jQuery.ready );}

jQuery中的就绪函数做了很多事情。坦率地说,我不认为替换它有什么意义,除非你的网站输出非常小。jQuery是一个非常小的库,它处理各种你以后需要的跨浏览器的东西。

无论如何,在这里发布它没有什么意义,只需打开jQuery并查看bindReady方法。

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

把你的<script>/*JavaScript code*/</script>闭幕前</body>标签。

不可否认,这可能不适合每个人的目的,因为它需要更改超文本标记语言文件,而不仅仅是在JavaScript文件document.ready中做一些事情,但仍…

我最近在一个移动网站上使用它。这是John Resig从“Pro JavaScript技术”中获得的简化版本。它取决于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;})();

编辑:

这是jQuery就绪的可行替代品

function ready(callback){// in case the document is already renderedif (document.readyState!='loading') callback();// modern browserselse if (document.addEventListener) document.addEventListener('DOMContentLoaded', callback);// IE <= 8else 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 1.6.2源的jQuery.ready()

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 #6781readyWait: 1,// Hold (or release) the ready eventholdReady: function( hold ) {if ( hold ) {ReadyObj.readyWait++;} else {ReadyObj.ready( true );}},// Handle when the DOM is readyready: function( wait ) {// Either a released hold or an DOMready/load event and not yet readyif ( (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 readyReadyObj.isReady = true;// If a normal DOM Ready event fired, decrement, and wait if need beif ( wait !== true && --ReadyObj.readyWait > 0 ) {return;}// If there are functions bound, to executereadyList.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 readyreturn setTimeout( ReadyObj.ready, 1 );}
// Mozilla, Opera and webkit nightlies currently support this eventif ( document.addEventListener ) {// Use the handy event callbackdocument.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );// A fallback to window.onload, that will always workwindow.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 iframesdocument.attachEvent( "onreadystatechange", DOMContentLoaded );
// A fallback to window.onload, that will always workwindow.attachEvent( "onload", ReadyObj.ready );
// If IE and not a frame// continually check to see if the document is readyvar toplevel = false;
try {toplevel = window.frameElement == null;} catch(e) {}
if ( document.documentElement.doScroll && toplevel ) {doScrollCheck();}}},_Deferred: function() {var // callbacks listcallbacks = [],// stored [ context , args ]fired,// to avoid firing when already doing sofiring,// flag to know if the deferred has been cancelledcancelled,// the deferred itselfdeferred  = {
// 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 argsresolveWith: 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 argumentsresolve: function() {deferred.resolveWith( this, arguments );return this;},
// Has this deferred been resolved?isResolved: function() {return !!( firing || fired );},
// Cancelcancel: 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 Explorerfunction 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 functionsReadyObj.ready();}// Cleanup functions for the document ready methodif ( 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 listenersReadyObj.bindReady();
var type = ReadyObj.type( fn );
// Add the callbackreadyList.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*/})

值得一看岩石固体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;};}};}();
// UsageaddEvent(window, 'unload', EventCache.flush);addEvent(window, 'load', function(){alert("I'm ready");});

穷人的解决方案:

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!");};})()

查看小提琴

这个解决方案怎么样?

// other onload attached earlierwindow.onload=function() {alert('test');};
tmpPreviousFunction=window.onload ? window.onload : null;
// our onload functionwindow.onload=function() {alert('another message');
// execute previous oneif (tmpPreviousFunction) tmpPreviousFunction();};

jQuery的答案对我很有用。经过一点重新设计,它很适合我的需求。希望对大家有帮助

function onReady ( callback ){var addListener = document.addEventListener || document.attachEvent,removeListener =  document.removeEventListener || document.detachEventeventName = document.addEventListener ? "DOMContentLoaded" : "onreadystatechange"
addListener.call(document, eventName, function(){removeListener( eventName, arguments.callee, false )callback()}, false )}

只需将其添加到超文本标记语言页面的底部…

<script>Your_Function();</script>

因为,超文本标记语言文档是由自上而下解析的。

三种选择:

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

准备状态改变

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

来源:MDN

DOM内容加载

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

关注石器时代浏览器:转到jQuery源代码并使用ready函数。在这种情况下,您不会解析+执行整个库,您只做了其中的一小部分。

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

function doTheMagic(counter) {alert("It worked on " + counter);}
// wait for document ready then call handler functionvar checkLoad = function(counter) {counter++;if (document.readyState != "complete" && counter<1000) {var fn = function() { checkLoad(counter); };setTimeout(fn,10);} else doTheMagic(counter);};checkLoad(0);

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

var docLoaded = setInterval(function () {if(document.readyState !== "complete") return;clearInterval(docLoaded);
/*Your code goes here i.e. init()*/}, 30);

在jsfiddle中显示警报

我用这个:

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

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

如果您在BODY底部附近加载jQuery,但在编写jQuery()或jQuery(documents). read()的代码时遇到问题,请在Github上查看jqShim

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

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

编辑@duskhuff的编辑以支持Internet Explorer 8。不同之处在于使用匿名函数对regex和setTimeout的函数测试进行了新的调用。

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

function ready(f){/in/.test(document.readyState)?setTimeout(function(){ready(f);},99):f();}

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

window.onReady = function onReady(fn){document.body ? fn() : setTimeout(function(){ onReady(fn);},50);};

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

该问题尤其出现在旧版Internet Explorer(最多8个)中。

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

1) dynamic or static HTML2) cached or non cached requests3) size of the complete HTML document4) chunked or non chunked transfer encoding

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

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

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

真的,如果你只关心Internet Explorer 9+,这段代码足以替换jQuery.ready

    document.addEventListener("DOMContentLoaded", callback);

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

domReady: function (callback) {// Mozilla, Opera and WebKitif (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();}}},

一旦DOM准备就绪,这个跨浏览器代码将调用一个函数:

var domReady=function(func){var scriptText='('+func+')();';var scriptElement=document.createElement('script');scriptElement.innerText=scriptText;document.body.appendChild(scriptElement);};

以下是它的工作原理:

  1. domReady的第一行调用函数的#1方法以获取您传入的函数的字符串表示形式,并将其包装在立即调用该函数的表达式中。
  2. domReady的其余部分使用表达式创建一个脚本元素并将其附加到文档的body
  3. 浏览器在DOM准备就绪后运行附加到body的脚本标记。

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

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

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

这个问题是很久以前提出的。对于任何看到这个问题的人来说,现在有一个名为“你可能不需要jQuery”的站点,它按所需的IE支持级别分解了jQuery的所有功能,并提供了一些替代的、较小的库。

根据你可能不需要jQuery的IE8文档就绪脚本

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

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

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

看看这个回答

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

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

因此,当页面准备就绪时,即DOMContentLoade,才会调用函数function_name()。

对于IE9+:

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

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

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

就你的问题而言,我从上面的链接中获取了下面的代码:)唯一的警告是它只适用于Internet Explorer 9和更高版本。

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

这是我使用的,它很快,涵盖了我认为的所有基础;适用于除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设置一个事件侦听器是可用的(交互式)。

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

如果你想等到所有资源都加载完毕,所有显示的图像等,然后使用window.onload。

如果您不必支持非常旧的浏览器,这里有一种方法可以做到这一点,即使您的外部脚本加载了async属性:

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

我只是使用:

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

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

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

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

试试这个:

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!");});
(function(f){if(document.readyState != "loading") f();else document.addEventListener("DOMContentLoaded", f);})(function(){console.log("The Document is ready");});

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

下面的代码仅在文档的readyState不是interactivecomplete时才检查DOMContentLoaded

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!});

最小和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 renderedif (document.readyState!='loading') run();// modern browserselse if (document.addEventListener)document.addEventListener('DOMContentLoaded', run);// IE <= 8else document.attachEvent('onreadystatechange', function(){if (document.readyState=='complete') run();});

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

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

例如:

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

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

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

比较

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

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

<html>
<head><script>// solution Aconsole.log(`[timestamp: ${Date.now()}] A: Head script`) ;    
// solution Bdocument.addEventListener("DOMContentLoaded", () => {print(`[timestamp: ${Date.now()}] B: DOMContentLoaded`);});
// solution Cdocument.addEventListener('readystatechange', () => {print(`[timestamp: ${Date.now()}] C: ReadyState: ${document.readyState}`);});   
// solution Ddocument.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 Ffunction bodyOnLoad() {print(`[timestamp: ${Date.now()}] F: <body onload='...'>`);infoAboutOnLoad(); // additional info}    
// solution Xdocument.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 Gprint(`[timestamp: ${Date.now()}] G: <body> bottom script`);</script></body>
</html>

适用于所有已知的浏览器(通过BrowserStack测试)。IE6+,Safari1+,Chrome1+,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 optimalreadyState 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 IEvar jscript_version = Number( new Function("/*@cc_on return @_jscript_version; @*\/")() ) || NaN;    
// check if the DOM has already loadedif (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 addEventListenerAnd 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} elseif (aev in window) { window[aev]('onload', ready);/* Old Opera has a default of window.attachEvent being falsy, so we use the in operator insteadhttps://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 addEventListenernor "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 workaddOnload(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 readyif ( 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 functionsfor (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 queuefor (; 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 functionif (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 functionsfor (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);} elseif (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>

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

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>

2022版本

在2022年,你所需要做的就是在你的脚本上放置deer属性,并将其加载到头部!

参考: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>

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

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