简体   繁体   English

$(document).ready 没有 jQuery 的等价物

[英]$(document).ready equivalent without jQuery

I have a script that uses $(document).ready , but it doesn't use anything else from jQuery.我有一个使用$(document).ready的脚本,但它不使用 jQuery 中的任何其他内容。 I'd like to lighten it up by removing the jQuery dependency.我想通过删除 jQuery 依赖项来减轻它。

How can I implement my own $(document).ready functionality without using jQuery?如何在不使用 jQuery 的情况下实现自己的$(document).ready功能? I know that using window.onload will not be the same, as window.onload fires after all images, frames, etc. have been loaded.我知道使用window.onload会不一样,因为window.onload在所有图像、框架等都加载后触发。

There is a standards based replacement, DOMContentLoaded that is supported by over 99% of browsers , though not IE8:有一个基于标准的替代品DOMContentLoaded被超过99% 的浏览器支持,尽管 IE8 不支持:

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

jQuery's native function is much more complicated than just window.onload, as depicted below. 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 );
}

Edit:编辑:

Here is a viable replacement for jQuery ready这是 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
});

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

Another good domReady function here taken from https://stackoverflow.com/a/9899701/175071另一个很好的 domReady 函数取自https://stackoverflow.com/a/9899701/175071


As the accepted answer was very far from complete, I stitched together a "ready" function like jQuery.ready() based on jQuery 1.6.2 source:由于接受的答案远未完成,我将基于 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 #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;
})();

How to use:如何使用:

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

I am not sure how functional this code is, but it worked fine with my superficial tests.我不确定这段代码的功能如何,但它在我的表面测试中运行良好。 This took quite a while, so I hope you and others can benefit from it.这花了相当长的时间,所以我希望你和其他人可以从中受益。

PS.: I suggest compiling it. PS.:我建议编译它。

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

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

or the native function if you only need to support the new browsers (Unlike jQuery ready, this won't run if you add this after the page has loaded)或者原生函数,如果你只需要支持新的浏览器(与 jQuery 不同,如果你在页面加载后添加它,这将不会运行)

document.addEventListener('DOMContentLoaded',function(){/*fun code to run*/})

Three options:三个选项:

  1. If script is the last tag of the body, the DOM would be ready before script tag executes如果script是 body 的最后一个标签,则 DOM 将在 script 标签执行之前准备好
  2. When the DOM is ready, "readyState" will change to "complete"当 DOM 准备就绪时,“readyState”将变为“完成”
  3. Put everything under 'DOMContentLoaded' event listener将所有内容放在“DOMContentLoaded”事件侦听器下

onreadystatechange onreadystatechange

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

Source: MDN来源: MDN

DOMContentLoaded DOMContentLoaded

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

Concerned about stone age browsers: Go to the jQuery source code and use the ready function.关注石器时代的浏览器:进入jQuery源码,使用ready函数。 In that case you are not parsing+executing the whole library you're are doing only a very small part of it.在这种情况下,您不会解析+执行整个库,而您正在做的只是其中的一小部分。

Place your <script>/*JavaScript code*/</script> right before the closing </body> tag.将您的<script>/*JavaScript code*/</script>放在结束</body>标记之前。

Admittedly, this might not suit everyone's purposes since it requires changing the HTML file rather than just doing something in the JavaScript file a la document.ready , but still...诚然,这可能不适合每个人的目的,因为它需要更改 HTML 文件,而不仅仅是在 JavaScript 文件中做一些事情,比如document.ready ,但仍然......

Poor man's solution:穷人的解决方法:

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

checkLoad();  

View Fiddle查看小提琴

Added this one, a bit better I guess, own scope, and non recursive添加了这个,我猜更好一点,自己的范围,并且非递归

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

View Fiddle查看小提琴

I use this:我用这个:

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

Note: This probably only works with newer browsers, especially these: http://caniuse.com/#feat=domcontentloaded注意:这可能只适用于较新的浏览器,尤其是这些: http ://caniuse.com/#feat=domcontentloaded

It is year 2020 and <script> tag has defer attribute.现在是 2020 年, <script>标签具有defer属性。

for example:例如:

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

it specifies that the script is executed when the page has finished parsing.它指定当页面完成解析时执行脚本。

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

Really, if you care about Internet Explorer 9+ only, this code would be enough to replace jQuery.ready :真的,如果您只关心Internet Explorer 9+ ,则此代码足以替换jQuery.ready

    document.addEventListener("DOMContentLoaded", callback);

If you worry about Internet Explorer 6 and some really strange and rare browsers, this will work:如果您担心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();
        }
    }
},

This question was asked quite a long time ago.这个问题很久以前就被问过了。 For anyone just seeing this question, there is now a site called "you might not need jquery" which breaks down - by level of IE support required - all the functionality of jquery and provides some alternative, smaller libraries.对于刚刚看到这个问题的任何人,现在有一个名为“您可能不需要 jquery”的站点,它分解了 - 按所需的 IE 支持级别 - jquery 的所有功能,并提供了一些替代的、更小的库。

IE8 document ready script according to you might not need 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();
        });
}

Cross-browser (old browsers too) and a simple solution:跨浏览器(旧浏览器也是)和一个简单的解决方案:

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

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

Showing alert in jsfiddle在 jsfiddle 中显示警报

I was recently using this for a mobile site.我最近将其用于移动网站。 This is John Resig's simplified version from "Pro JavaScript Techniques".这是 John Resig 的“Pro JavaScript Techniques”的简化版本。 It depends on addEvent.这取决于 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;
})();

2022 version 2022版

In 2022, all you need to do is put the defer attribute on your script, and load it in the head!在 2022 年,你需要做的就是把 defer 属性放在你的脚本上,然后加载到 head 中!

Reference: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script#attr-defer参考: 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>

The jQuery answer was pretty useful to me. jQuery 答案对我非常有用。 With a little refactory it fitted my needs well.通过一点重构,它很好地满足了我的需求。 I hope it helps anybody else.我希望它可以帮助其他人。

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

Here is the smallest code snippet to test DOM ready which works across all browsers (even IE 8):这是测试 DOM 就绪的最小代码片段,它适用于所有浏览器(甚至 IE 8):

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

See this answer .看到这个答案

Just add this to the bottom of your HTML page...只需将其添加到 HTML 页面的底部...

<script>
    Your_Function();
</script>

Because, HTML documents are parsed by top-bottom.因为,HTML 文档是由 top-bottom 解析的。

Most minimal and 100% working最小和 100% 工作

I have picked the answer from PlainJS and it's working fine for me.我从PlainJS中选择了答案,它对我来说很好用。 It extends DOMContentLoaded so that it can be accepted at all the browsers.它扩展了DOMContentLoaded以便它可以被所有浏览器接受。


This function is the equivalent of jQuery's $(document).ready() method:这个函数相当于 jQuery 的$(document).ready()方法:

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

However, in contrast to jQuery, this code will only run properly in modern browsers (IE > 8) and it won't in case the document is already rendered at the time this script gets inserted (eg via Ajax).然而,与 jQuery 相比,此代码只能在现代浏览器 (IE > 8) 中正常运行,并且在插入此脚本时文档已经呈现的情况下(例如通过 Ajax)将无法正常运行。 Therefore, we need to extend this a little bit:因此,我们需要稍微扩展一下:

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

This covers basically all possibilities and is a viable replacement for the jQuery helper.这基本上涵盖了所有可能性,并且是 jQuery 助手的可行替代品。

It is worth looking in Rock Solid addEvent() and http://www.braksator.com/how-to-make-your-own-jquery . Rock Solid addEvent()http://www.braksator.com/how-to-make-your-own-jquery值得一看。

Here is the code in case the site goes down这是网站出现故障时的代码

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

It's always good to use JavaScript equivalents as compared to jQuery.与 jQuery 相比,使用 JavaScript 等价物总是好的。 One reason is one fewer library to depend on and they are much faster than the jQuery equivalents.一个原因是依赖的库少了一个,而且它们比 jQuery 等价物快得多。

One fantastic reference for jQuery equivalents is http://youmightnotneedjquery.com/ . jQuery 等价物的一个很好的参考是http://youmightnotneedjquery.com/

As far as your question is concerned, I took the below code from the above link :) Only caveat is it only works with Internet Explorer 9 and later.就您的问题而言,我从上面的链接中获取了以下代码 :) 唯一需要注意的是它仅适用于Internet Explorer 9及更高版本。

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

This cross-browser code will call a function once the DOM is ready:一旦 DOM 准备好,此跨浏览器代码将调用一个函数:

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

Here's how it works:以下是它的工作原理:

  1. The first line of domReady calls the toString method of the function to get a string representation of the function you pass in and wraps it in an expression that immediately calls the function. domReady的第一行调用函数的toString方法来获取您传入的函数的字符串表示形式,并将其包装在立即调用该函数的表达式中。
  2. The rest of domReady creates a script element with the expression and appends it to the body of the document. domReady的其余部分使用表达式创建一个脚本元素并将其附加到文档的body中。
  3. The browser runs script tags appended to body after the DOM is ready. DOM 准备好后,浏览器运行附加到body的脚本标签。

For example, if you do this: domReady(function(){alert();});例如,如果您这样做: domReady(function(){alert();}); , the following will appended to the body element: ,以下将附加到body元素:

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

Note that this works only for user-defined functions.请注意,这仅适用于用户定义的函数。 The following won't work: domReady(alert);以下将不起作用: domReady(alert);

How about this solution?这个解决方案怎么样?

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

We found a quick-and-dirty cross browser implementation of ours that may do the trick for most simple cases with a minimal implementation:我们发现了一个快速而简单的跨浏览器实现,它可以用最少的实现来解决大多数简单的情况:

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

I simply use:我只是使用:

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

And unlike document.addEventListener("DOMContentLoaded" //etc as in the very top answer, it works as far back as IE9 -- http://caniuse.com/#search=DOMContentLoaded only indicates as recently as IE11.与最上面的答案中的document.addEventListener("DOMContentLoaded" //etc不同,它可以追溯到 IE9 —— http://caniuse.com/#search=DOMContentLoaded仅表示最近到 IE11。

Interestingly I stumbled upon this setTimeout solution in 2009: Is checking for the readiness of the DOM overkill?有趣的是,我在 2009 年偶然发现了这个setTimeout解决方案: 检查 DOM 的准备情况是否矫枉过正? , which probably could have been worded slightly better, as I meant "is it overkill to use various frameworks' more complicated approaches to check for the readiness of the DOM". ,这可能措辞稍微好一点,因为我的意思是“使用各种框架的更复杂的方法来检查 DOM 的准备情况是否过度”。

My best explanation for why this technique works is that, when the script with such a setTimeout has been reached, the DOM is in the middle of being parsed, so execution of the code within the setTimeout gets deferred until that operation is finished.对于这种技术为什么有效,我最好的解释是,当到达具有这种 setTimeout 的脚本时,DOM 正在被解析,因此 setTimeout 内的代码的执行被推迟到该操作完成。

Comparison比较

Here (in below snippet) is comparison of chosen available browser "built-in" methods and their execution sequence.这里(在下面的片段中)是选择的可用浏览器“内置”方法及其执行顺序的比较。 Remarks评论

  • the document.onload (X) is not supported by any modern browser (event is never fired )任何现代浏览器都不支持document.onload (X) (从不触发事件)
  • if you use <body onload="bodyOnLoad()"> (F) and at the same time window.onload (E) then only first one will be executed (because it override second one)如果您使用<body onload="bodyOnLoad()"> (F) 并同时使用window.onload (E) 则只会执行第一个(因为它会覆盖第二个)
  • event handler given in <body onload="..."> (F) is wrapped by additional onload function <body onload="..."> (F) 中给出的事件处理程序由附加的onload函数包装
  • document.onreadystatechange (D) not override document .addEventListener('readystatechange'...) (C) probably cecasue onXYZevent-like methods are independent than addEventListener queues (which allows add multiple listeners). document.onreadystatechange (D) 不覆盖document .addEventListener('readystatechange'...) (C) 可能会导致onXYZevent-like方法独立于addEventListener队列(允许添加多个侦听器)。 Probably nothing happens between execution this two handlers.执行这两个处理程序之间可能没有任何反应。
  • all scripts write their timestamp in console - but scripts which also have access to div write their timestamps also in body (click "Full Page" link after script execution to see it).所有脚本都在控制台中写入它们的时间戳 - 但也可以访问div的脚本也在正文中写入它们的时间戳(在脚本执行后单击“整页”链接以查看它)。
  • solutions readystatechange (C,D) are executed multiple times by browser but for different document states:解决方案readystatechange (C,D) 由浏览器多次执行,但针对不同的文档状态:
  • loading - the document is loading (no fired in snippet) loading - 文档正在加载(没有在代码段中触发)
  • interactive - the document is parsed, fired before DOMContentLoaded交互式- 文档被解析,在DOMContentLoaded之前触发
  • complete - the document and resources are loaded, fired before body/window onload完成- 加载文档和资源,在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>

Simplest way using pure JavaScript.使用纯 JavaScript 的最简单方法。 Without jQuery:没有 jQuery:

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

If you don't have to support very old browsers, here is a way to do it even when your external script is loaded with async attribute:如果您不必支持非常旧的浏览器,即使您的外部脚本加载了异步属性,也可以使用以下方法:

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

This should work:这应该有效:

document.addEventListener('DOMContentLoaded', function() {
 /* alert('Page loaded!');
 some code 
 more code */
});

The setTimeout/setInterval solutions presented here will only work in specific circumstances.此处介绍的 setTimeout/setInterval 解决方案仅适用于特定情况。

The problem shows up especially in older Internet Explorer versions up to 8.该问题尤其出现在不超过 8 的旧 Internet Explorer 版本中。

The variables affecting the success of these setTimeout/setInterval solutions are:影响这些 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

the original (native Javascript) code solving this specific issue is here:解决此特定问题的原始(本机 Javascript)代码在这里:

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

this is the code from which the jQuery team have built their implementation.这是 jQuery 团队构建实现的代码。

For IE9+:对于 IE9+:

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

Here's what I use, it's fast and covers all bases I think;这是我使用的,它速度快,涵盖了我认为的所有基础; works for everything except IE<9.适用于除 IE<9 之外的所有内容。

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

This seems to catch all cases:这似乎涵盖了所有情况:

  • fires immediately if the DOM is already ready (if the DOM is not "loading", but either "interactive" or "complete")如果 DOM 已经准备好,则立即触发(如果 DOM 不是“正在加载”,而是“交互式”或“完成”)
  • if the DOM is still loading, it sets up an event listener for when the DOM is available (interactive).如果 DOM 仍在加载,它会为 DOM 可用(交互式)设置一个事件侦听器。

The DOMContentLoaded event is available in IE9 and everything else, so I personally think it's OK to use this. DOMContentLoaded 事件在 IE9 和其他所有东西中都可用,所以我个人认为使用它是可以的。 Rewrite the arrow function declaration to a regular anonymous function if you're not transpiling your code from ES2015 to ES5.如果您没有将代码从 ES2015 转换为 ES5,请将箭头函数声明重写为常规匿名函数。

If you want to wait until all assets are loaded, all images displayed etc then use window.onload instead.如果您想等到所有资产都加载完毕,显示所有图像等,然后使用 window.onload 代替。

Nowadays you should use modules.现在你应该使用模块。 Put your code into the default function of a module and import the function into a script element.将您的代码放入模块的默认函数中,然后将该函数导入脚本元素中。

client.js : client.js

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

index.html : 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>

If you are loading jQuery near the bottom of BODY, but are having trouble with code that writes out jQuery(<func>) or jQuery(document).ready(<func>), check out jqShim on Github.如果您在 BODY 底部附近加载 jQuery,但在写出 jQuery(<func>) 或 jQuery(document).ready(<func>) 的代码时遇到问题,请查看 Github 上的jqShim

Rather than recreate its own document ready function, it simply holds onto the functions until jQuery is available then proceeds with jQuery as expected.它不是重新创建自己的文档就绪函数,而是简单地保留这些函数,直到 jQuery 可用,然后按预期继续使用 jQuery。 The point of moving jQuery to the bottom of body is to speed up page load, and you can still accomplish it by inlining the jqShim.min.js in the head of your template.将 jQuery 移到 body 底部的目的是加快页面加载速度,您仍然可以通过在模板头部内联 jqShim.min.js 来完成它。

I ended up writing this code to make moving all the scripts in WordPress to the footer, and just this shim code now sits directly in the header.我最终编写了这段代码来将WordPress中的所有脚本移动到页脚,而现在只有这个 shim 代码直接位于页眉中。

This approach is the shortest way I can think of. 这种方法是我能想到的最短的方法。

The solution based on the DOMContentLoaded event only works if the script is loaded before the document, whereas the lazy check suggested here ensures the code is executed always, even in scripts loaded dynamically later on, exactly as the JQuery's document ready. 仅当脚本在文档之前加载时,基于DOMContentLoaded事件的解决方案才有效,而此处建议的延迟检查可确保始终执行代码,即使在以后动态加载的脚本中也是如此,就像JQuery的文档准备就绪一样。

This code is compatible with all browsers (including some legacy, down to IE6 and Safari for Windows). 此代码与所有浏览器(包括某些旧版,IE6和Safari for Windows)兼容。

(function ready() {
    if (!document.body) {setTimeout(ready, 50); return;}
    // Document is ready here
})();
function onDocReady(fn){ 
    $d.readyState!=="loading" ? fn():document.addEventListener('DOMContentLoaded',fn);
}

function onWinLoad(fn){
    $d.readyState==="complete") ? fn(): window.addEventListener('load',fn);
} 

onDocReady provides a callback when the HTML dom is ready to fully access/parse/manipulate.当 HTML dom 准备好完全访问/解析/操作时, onDocReady提供回调。

onWinLoad provides a callback when everything has loaded (images etc) onWinLoad在所有内容(图像等)加载完毕后提供回调

  • These functions can be called whenever you want.您可以随时调用这些函数。
  • Supports multiple "listeners".支持多个“侦听器”。
  • Will work in any browser.将在任何浏览器中工作。
(function(f){
  if(document.readyState != "loading") f();
  else document.addEventListener("DOMContentLoaded", f);
})(function(){
  console.log("The Document is ready");
});

Most vanilla JS Ready functions do NOT consider the scenario where the DOMContentLoaded handler is set after the document is already loaded - Which means the function will never run .大多数 vanilla JS Ready 函数不考虑在文档已经加载设置DOMContentLoaded处理程序的场景 - 这意味着该函数将永远不会运行 This can happen if you look for DOMContentLoaded within an async external script ( <script async src="file.js"></script> ).如果您在async外部脚本 ( <script async src="file.js"></script> ) 中查找DOMContentLoaded ,就会发生这种情况。

The code below checks for DOMContentLoaded only if the document's readyState isn't already interactive or complete .下面的代码仅在文档的readyState不是interactivecomplete时检查DOMContentLoaded

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

If you want to support IE aswell:如果你也想支持 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!
});

Works in all known browsers (tested via BrowserStack).适用于所有已知的浏览器(通过 BrowserStack 测试)。 IE6+, Safari 1+, Chrome 1+, Opera, etc. Uses DOMContentLoaded , with fallbacks to document.documentElement.doScroll() and window.onload . 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();
    }
}

Usage:用法:

<script>
DOMContentLoaded(function(e) { console.log(e) });
</script>

This was a good https://stackoverflow.com/a/11810957/185565 poor man's solution.这是一个很好的https://stackoverflow.com/a/11810957/185565穷人的解决方案。 One comment considered a counter to bail out in case of emergency.有一条评论认为是在紧急情况下采取救助措施。 This is my modification.这是我的修改。

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

Edit of the edit of @duskwuff to support Internet Explorer 8 too. @duskwuff 的编辑也支持Internet Explorer 8 The difference is a new call to the function test of the regex and the setTimeout with an anonymous function.不同之处在于对正则表达式的函数测试和带有匿名函数的 setTimeout 的新调用。

Also, I set the timeout to 99.另外,我将超时设置为 99。

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

Try this:尝试这个:

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

The ready function in jQuery does a number of things. jQuery中的 ready 函数做了很多事情。 Frankly, I don't see that point of replacing it unless you have amazingly small output from your website.坦率地说,除非您的网站输出非常少,否则我看不到替换它的意义。 jQuery is a pretty tiny library, and it handles all sorts of cross-browser things you'll need later. jQuery是一个非常小的库,它处理你以后需要的各种跨浏览器的东西。

Anyway, there's little point in posting it here, just open up jQuery and look at the bindReady method.反正这里贴出来没什么意义,直接打开jQuery看看bindReady方法就行了。

It starts by calling either document.addEventListener("DOMContentLoaded") or document.attachEvent('onreadystatechange') depending on the event model, and goes on from there.它首先根据事件模型调用document.addEventListener("DOMContentLoaded")document.attachEvent('onreadystatechange') ,然后从那里继续。

In short, instead of the $(document).ready() used in jQuery, we can use a JavaScript method:简而言之,我们可以使用 JavaScript 方法来代替 jQuery 中使用的 $(document).ready():

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

Thus, when the page is ready ie DOMContentLoaded only then the function function_name() will be invoked.因此,当页面准备好时,即只有 DOMContentLoaded 时,函数 function_name() 将被调用。

If you want to support Internet Explorer 7+ (no quirks, compatibility and other pain), last Chrome , last Safari , last Firefox and no iframes - this will be enough:如果你想支持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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM