$(document).ready等同于没有jQuery


2015

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

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


296
...而且绝对不一样的功能。
Joel Mueller

40
就像这个答案指出的那样,如果您只想从jQuery获得内容$(document).ready,则可以通过在页面的底部而不是顶部运行代码来轻松解决该问题。HTML5Boilerplate使用此精确方法。
Blazemonger 2013年


我将通话放在文档的最后,这解决了我的问题。调用该函数时,将加载所有内容。
IgniteCoders 2014年

Answers:


1440

有一个基于标准的替代品,DOMContentLoaded超过98%的浏览器都支持它,尽管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 );
}

19
在实际工作普通的JavaScript执行在这里如果有人想代码,才可以刚落于:stackoverflow.com/questions/9899372/...
jfriend00

4
jQuery DOM就绪代码似乎已简化:github.com/jquery/jquery/blob/master/src/core/ready.js
Jose Nobile

2
@JoseNobile,因为他们放弃了旧版浏览器支持
huysentruitw 2015年

16
我认为我们已经准备好从IE8继续前进...;)。感谢您的链接,@ JoseNobile。
Con Antonakos

13
如果随后加载脚本,则DOMContentLoaded将不起作用。准备就绪的JQuery文档将始终执行。
贾里德·英塞尔

343

编辑:

这是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 ready不同,如果在页面加载后添加此功能,则该功能将无法运行)

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

14
@TimoHuovinen替代方案:Zepto.js(9.1 kb),Snack.js(8.1 kb),$ dom(2.3 kb)和140 Medley(0.5 kb)。编辑:您也可以看看Ender。
Frederik Krautwald

2
@FrederikKrautwald $ dom听起来像我想要的,但不确定是否合适。Zepto看起来也非常有前途,感谢您的分享!
Timo Huovinen 2014年

@TimoHuovinen如果您还没有看过Ender,那么绝对应该看看enderjs.com
Frederik Krautwald

2
@Timo Huovinen:您的问题的确非常广泛!创建jQuery时,它解决了许多跨浏览器问题,这些问题由当今不太重要的浏览器产生。如今,“仅javascript”比以前更容易。目前,创建“包含所有内容的20kb大压缩文件”无疑是个好主意,原因有很多,我不想列出所有内容。
dotpush 2014年

1
我不喜欢这样 如果人们喜欢这个答案,请问自己为什么首先要删除jQuery。如果您只是要提取完全相同的功能,而浏览器的所有后备膨胀都重新打包到包中,则这毫无意义。首先不是要避免jQuery的全部意义吗?
菲尔(Phil)

207

三种选择:

  1. 如果 script是正文的最后一个标签,则在执行脚本标签之前,DOM已准备就绪
  2. DOM准备就绪后,“ readyState”将更改为“ complete”
  3. 将所有内容置于“ DOMContentLoaded”事件侦听器下

就绪状态变更

  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功能。在那种情况下,您没有解析+执行整个库,而是只执行了很小一部分。


3
第二个例子比标记的答案要优雅得多。为什么这个没有被标记为正确的呢?
0112年

2
仍然为DOMContentLoaded事物+1,它完全符合我的要求。
Tripleee 2014年

1
onreadystatechange帮了我大忙...在异步jquery加载后需要运行一些脚本。
亚伯兰

2
就像FYI一样,#1并非完全正确。在DOM完成之前,很有可能在页面末尾加载脚本。这就是为什么听众表现出色的原因。他们在浏览器完成后进行监听。放到最后,这让您不胜其烦,因为脚本加载的速度比浏览器的渲染速度慢。
Machavity

1
如果文档已经完成加载,则此变体也将起作用,如果可以的话,请更新您的(imo最佳)答案:if(document.readyState =='complete'){init(); } else {document.onreadystatechange = function(){if(document.readyState =='complete'){init(); }}}
ZPiDER

87

将您的<script>/*JavaScript code*/</script>权利放在结束 </body>标记之前

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


在我看来,存在兼容性问题,例如,由于该页面尚未准备就绪,因此您无法在这些浏览器中执行此操作。不幸的是,我记不清了。尽管如此,在所有案例中有99%都采用了足够接近的方式+1(由Yahoo!建议)。
Boldewyn

7
实际上,将脚本元素放在页面底部是一个几乎完美的解决方案。它可以跨浏览器工作并模拟document.ready完美。唯一的缺点是,它比使用一些智能代码更具吸引力,您将不得不要求正在创建的脚本的用户添加一个额外的脚本片段来调​​用您的ready或init函数。
Stijn de Witt

@StijndeWitt-您必须调用init函数意味着什么?使用document.ready的脚本不需要其他客户端代码来调用它,它是自包含的,并且等效于主体末尾包含代码的脚本也可以是自包含的,并且不需要需要其他代码来调用它。
nnnnnn

1
为什么不把剧本的结束标记,而收盘前</html>的标签?
查尔斯·霍尔布劳

1
@CharlesHolbrow尽管所有浏览器都会正确解释它,但如果您希望它是有效的html,则html标记应仅包含headbody
阿尔瓦罗·蒙托罗

66

穷人的解决方案:

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

查看小提琴


8
@PhilipLangford或仅将其放在a内setInterval并完全删除递归。
Alex W

1
@Raveren,嗯,您是对的,我敢肯定我在发布它时已经对其进行了测试。无论如何,它变得更加简单,现在该函数被调用,不再需要包装。
雅各布·斯特恩伯格

24
这不是性感的。不好意思 使用计时器/间隔来检测事物可能是“有效的”,但如果您继续像这样进行编程,那么任何值得其投入的更大项目都会大跌眼镜。不要像这样乱砍东西。做对了。请。这种代码会伤害开发生态系统,因为有了更好的解决方案,您就知道了。
dudewad 2014年

1
我认为这个答案更接近ustindiaz.com/smallest-domready-ever,所以我改进了脚本:jsfiddle.net/iegik/PT7x9
iegik 2014年

1
@ReidBlomquist是的,这是一种“错误”的方式,这就是我要指出的(尽管有点坚决,我知道)。您可能会说,如果做错了,就可以以某种方式“帮助”生态系统,但是问题在于,人们因为没有经验的知识而不得不使用大量的“好”代码,因此他们选择了不好的代码不会对生态系统有帮助,因为那样的话,他们将采用该错误代码并将其实现为实际的生产体系​​结构解决方案。因此,我想,我们只需要对这种“谬误”有不同的看法。
dudewad 2014年


21

确实,如果您只关心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();
        }
    }
},

18

这个问题是很久以前问过的。对于只看到这个问题的任何人,现在都有一个名为“您可能不需要jquery”的网站 按所需的IE支持级别细分了jquery的所有功能,并提供了一些替代的小型库。

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

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

我想知道为什么'onreadystatechange'需要而不是document.attachEvent('onload', fn);
卢克(Luke)

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

13
请谨慎使用此代码。它不等于$(document).ready。当document.body准备就绪时,此代码将触发回调,这不能保证DOM已完全加载。
Karolis 2011年

12

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

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

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

在jsfiddle中显示警报


除非加载DOM花费的时间超过30毫秒,否则您的代码将不会运行。
Quelklef

1
@Quelklef的setInterval不是setTimeout
Pawel

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

在某些浏览器中,removeListener将需要使用文档作为上下文来调用。removeListener.call(document, ...
罗恩

9

这是测试DOM就绪最小代码段,代码段可在所有浏览器(甚至是IE 8)上运行:

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

看到这个答案


6

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

<script>
    Your_Function();
</script>

因为,HTML文档是由上至下解析的。


7
您如何知道执行此代码时已构建DOM?包括已加载和已解析的CSS?浏览器API DOMContentLoaded是为此目的而设计的。
2014年

这实际上取决于他想对js做什么。如果页面完成时他是否真的需要执行某些操作。
davefrassoni

5

值得一看的是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");});

第二个链接断开。
彼得·莫滕森


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


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

3
您可以在带有“ load”的窗口上使用addEventListener。侦听器一个接一个地执行,不需要手动链接。
Zaffy 2013年

1
但是负载与准备不同。“加载”甚至发生在文档“就绪”之前。一个就绪的文档已加载了其DOM,而已加载的窗口并不一定具有DOM。很好的答案
Mzn

1
@Mzn:我认为这是倒退。我认为文档准备好发生窗口加载事件之前。“通常,不必等待所有图像完全加载。如果可以更早地执行代码,通常最好将其放置在发送给.ready()方法的处理程序中。” (api.jquery.com/load-event)–
泰勒·里克

这将覆盖页面上其余的window.onload事件,并会引起问题。它应该在现有事件之上添加事件。
Teoman shipahi

加载事件可能为时已晚。当依赖于第三方外部js / images时,使用它会很痛苦。您无法控制的无响应服务器,一切都会失败。使用DOMContentLoaded不仅是一种优化,而且更安全!
dotpush 2014年

3

与jQuery相比,使用JavaScript等效项总是好事。原因之一是要减少依赖的库,而且它们比jQuery等效库快得多。

http://youmightnotneedjquery.com/是jQuery等价物的绝佳参考。

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

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

3

极小且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帮助器的可行替代品。



2

我们找到了我们的快速,跨平台的跨浏览器实现,它可以在最简单的情况下以最小的实现实现成功:

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

什么doc.body!?
纳比·卡兹

2

这里介绍的setTimeout / setInterval解决方案仅在特定情况下有效。

尤其是在Internet Explorer 8以前的版本中,尤其是在出现此问题时。

影响这些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团队用来构建其实现的代码。


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,则将arrow函数声明重写为常规的匿名函数。

如果要等到所有资产都加载完毕,则显示的所有图像等将改为使用window.onload。


1

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

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

0

对于IE9 +:

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

0

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

与其重新创建自己的文档就绪功能,不如直接保留这些功能,直到jQuery可用,然后按预期使用jQuery。将jQuery移至正文底部的目的是加快页面加载速度,您仍然可以通过在模板头部内联jqShim.min.js来完成此任务。

我最终编写了这段代码,以使WordPress中的所有脚本都移至页脚,而现在,此填充代码直接位于页眉中。


0

尝试这个:

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

大声笑,你要运行两次回调
安德鲁

0
function onDocReady(fn){ 
    $d.readyState!=="loading" ? fn():document.addEventListener('DOMContentLoaded',fn);
}

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

当HTML dom准备完全访问/解析/操作时,onDocReady提供回调。

当所有内容加载完毕(图像等)时,onWinLoad提供回调

  • 您可以随时调用这些函数。
  • 支持多个“侦听器”。
  • 将可在任何浏览器中使用。

0
(function(f){
  if(document.readyState != "loading") f();
  else document.addEventListener("DOMContentLoaded", f);
})(function(){
  console.log("The Document is ready");
});

这有什么补充,而其他答案没有呢?
dwjohnston

它使用一个自包含的闭包(不填充全局“窗口”范围),它在所有浏览器上都可以使用,并且非常紧凑。我没有看到其他类似的答案。
达斯汀·普瓦桑

即使在DOM已经加载之后,它也可以工作(就像jQuery.ready一样),其中大多数答案都无法做到。
达斯汀·普瓦桑

0

大多数香草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!
});

0

我只是使用:

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

而且与document.addEventListener("DOMContentLoaded" //etc最高答案不同,它的工作最早可以追溯到IE9- http ://caniuse.com/#search=DOMContentLoaded仅表示IE11。

有趣的是,我setTimeout在2009年偶然发现了此解决方案:是否正在检查DOM是否已准备就绪?,这可能用更好的措辞来表达,因为我的意思是“使用各种框架的更复杂的方法来检查DOM的就绪性是否为时过早”。

我对这种技术为何有效的最好解释是,当到达具有这样的setTimeout的脚本时,DOM处于解析的中间,因此setTimeout中代码的执行将推迟到该操作完成之前。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.