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

Fly*_*wat 1925 javascript jquery

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

如何在$(document).ready不使用jQuery的情况下实现自己的功能?我知道使用window.onload不会是相同的,因为window.onload在加载了所有图像,帧等之后的火灾.

Cha*_*ant 1344

有一个基于标准的替代品,DOMContentLoaded超过98%的浏览器支持,但不是IE8:

document.addEventListener("DOMContentLoaded", function(event) { 
  //do work
});
Run Code Online (Sandbox Code Playgroud)

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 );
}
Run Code Online (Sandbox Code Playgroud)

  • 这里有一个实际工作的普通javascript实现,如果有人想要他们可以插入的代码:http://stackoverflow.com/questions/9899372/pure-javascript-equivalent-to-jquerys-ready-how-to-call-a-function - 当 - 的/ 9899701#9899701 (17认同)
  • 我想我们已经准备好从IE8继续......;).感谢@JoseNobile链接. (15认同)
  • 如果之后加载脚本,DOMContentLoaded将无法工作.JQuery文档随时可执行. (13认同)
  • jQuery DOM ready代码似乎被简化:https://github.com/jquery/jquery/blob/master/src/core/ready.js (4认同)
  • @JoseNobile因为他们删除了较旧的浏览器支持 (2认同)

Tim*_*nen 333

编辑:

这是jQuery ready的可行替代品

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
});
Run Code Online (Sandbox Code Playgroud)

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

另一个好的domReady功能来自/sf/answers/692979101/


由于接受的答案远非完整,我将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;
})();
Run Code Online (Sandbox Code Playgroud)

如何使用:

<script>
    ready(function(){
        alert('It works!');
    });
    ready(function(){
        alert('Also works!');
    });
</script>
Run Code Online (Sandbox Code Playgroud)

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

PS.:我建议编译它.

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

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

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

document.addEventListener('DOMContentLoaded',function(){/*fun code to run*/})
Run Code Online (Sandbox Code Playgroud)

  • @TimoHuovinen替代方案:Zepto.js(9.1 kb),Snack.js(8.1 kb),$ dom(2.3 kb)和140 Medley(0.5 kb).*编辑:*你也可以看看恩德. (14认同)
  • @FrederikKrautwald $ dom听起来像我想要的,但不确定它是否符合要求.Zepto看起来也很有前途,谢谢分享! (2认同)
  • @Timo Huovinen:你的问题非常非常广泛!当jQuery创建时,它适合了许多浏览器生成的跨浏览器问题,这些问题在今天不太重要.今天,"只有javascript"比它更容易.在这个时候,创建一个"包含所有内容的20kb大压缩"肯定是一个好主意,因为我不想将它们全部列出. (2认同)
  • 我不喜欢这个。如果人们更喜欢这个答案,请先问问自己为什么要放弃 jQuery。如果您只是要提取与所有浏览器回退膨胀完全相同的功能回到您的包中,这有点毫无意义。这不是一开始就避免使用 jQuery 的全部意义吗? (2认同)

Jha*_*bub 201

三种选择:

  1. 如果script是身体的最后一个标签时,DOM会前的脚本标记执行准备
  2. 当DOM准备就绪时,"readyState"将变为"complete"
  3. 将所有内容放在"DOMContentLoaded"事件侦听器下

的onreadystatechange

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

资料来源:MDN

DOMContentLoaded

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

关注石器时代的浏览器: 转到jQuery源代码并使用该ready函数.在这种情况下,你没有解析+执行整个库,你只做了很小的一部分.

  • 第二个例子比标记的答案更加优雅和简洁.为什么这个没有被标记为正确的? (3认同)
  • 对于DOMContentLoaded来说仍然是+1,它完全符合我的要求. (2认同)
  • onreadystatechange 对我有用……需要在异步 jquery 加载后运行一些脚本。 (2认同)
  • 就像一个FYI,#1并不完全正确.页面末尾的脚本很可能在DOM完成之前加载.这就是听众优越的原因.他们在浏览器完成时监听.把它放在最后是指责脚本加载比浏览器渲染慢. (2认同)
  • 当文档已完成加载时,此变体也将起作用,如果可以,请更新您的(imo 最佳)答案: if (document.readyState == 'complete') { init(); } else { document.onreadystatechange = function () { if (document.readyState == 'complete') { init(); } } } (2认同)

rob*_*rob 85

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

不可否认,这可能不适合每个人的目的,因为它需要更改HTML文件,而不是仅仅在JavaScript文件中执行某些操作document.ready,但仍然......

  • 实际上,将脚本元素放在页面底部是一个几乎完美的解决方案.它可以跨浏览器工作并模拟document.ready完美.唯一的缺点是,它比使用某些智能代码(有点)更突出,您将不得不向用户询问您正在创建的脚本,以添加额外的脚本片段来调​​用ready或init函数. (7认同)
  • @CharlesHolbrow 尽管所有浏览器都会正确解释它,但如果您希望它是有效的 html,则 [`html`](https://html.spec.whatwg.org/multipage/semantics.html#the-html-element)标签应该只包含 `head` 和 `body`。 (2认同)

Jak*_*erg 67

穷人的解决方案:

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

checkLoad();  
Run Code Online (Sandbox Code Playgroud)

查看小提琴

添加了这个,我想,自己的范围和非递归更好一点

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

查看小提琴

  • 这不性感.不,抱歉.使用定时器/间隔来检测东西可能"有效",但是如果你继续这样的编程,任何更大的项目都值得用盐.不要像这样一起破解东西.做对了.请.这种代码会损害开发生态系统,因为有一个更好的解决方案并且您知道它. (23认同)
  • @PhilipLangford或者只是将它放在`setInterval`中并完全删除递归. (8认同)

Dus*_*vis 34

我用这个:

document.addEventListener("DOMContentLoaded", function(event) { 
    //Do work
});
Run Code Online (Sandbox Code Playgroud)

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

  • 实际上是IE9及以上版本 (13认同)

Gre*_*reg 28

2022版

2022 年,您所需要做的就是在脚本上添加 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>
Run Code Online (Sandbox Code Playgroud)


Dan*_*Dan 21

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

    document.addEventListener("DOMContentLoaded", callback);
Run Code Online (Sandbox Code Playgroud)

如果您担心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();
        }
    }
},
Run Code Online (Sandbox Code Playgroud)


chu*_*die 18

很久以前就问过这个问题了.对于任何刚看到这个问题的人来说,现在有一个名为"你可能不需要jquery"的网站 ,它按照所需的IE支持级别进行细分 - 所有jquery的功能,并提供了一些替代的,更小的库.

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

function ready(fn) {
    if (document.readyState != 'loading')
        fn();
    else if (document.addEventListener)
        document.addEventListener('DOMContentLoaded', fn);
    else
        document.attachEvent('onreadystatechange', function() {
            if (document.readyState != 'loading')
                fn();
        });
}
Run Code Online (Sandbox Code Playgroud)


Mik*_*ser 14

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

例如:

<script src="demo_defer.js" defer></script>
Run Code Online (Sandbox Code Playgroud)

它指定在页面解析完成后执行脚本。

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

  • 很好,但仅适用于外部脚本。 (4认同)

小智 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;
})();
Run Code Online (Sandbox Code Playgroud)

  • 小心这段代码.它不等于$(document).ready.当document.body准备好时,此代码会触发回调,但不保证DOM已完全加载. (13认同)

Mie*_*ere 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 )
}
Run Code Online (Sandbox Code Playgroud)


Paw*_*wel 11

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

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

    /*
        Your code goes here i.e. init()
    */
}, 30);
Run Code Online (Sandbox Code Playgroud)

在jsfiddle中显示警报


Ant*_*Roy 9

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

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

看到这个答案.


dav*_*oni 6

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

<script>
    Your_Function();
</script>
Run Code Online (Sandbox Code Playgroud)

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

  • 你怎么知道在执行这段代码时构建了DOM?包括加载和解析的CSS?浏览器API DOMContentLoaded就是为此而设计的. (7认同)

Vat*_*sal 6

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

http://youmightnotneedjquery.com/是 jQuery 等效项的一个很棒的参考。

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

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


Ben*_*Ben 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");});
Run Code Online (Sandbox Code Playgroud)


Max*_*ber 5

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

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

它的工作原理如下:

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

例如,如果您执行以下操作:domReady(function(){alert();});,则以下内容将附加到该body元素:

 <script>(function (){alert();})();</script>
Run Code Online (Sandbox Code Playgroud)

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


Shi*_*rma 5

最低限度和 100% 工作

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


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

document.addEventListener('DOMContentLoaded', function(){
    // do something
});
Run Code Online (Sandbox Code Playgroud)

但是,与 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();
});
Run Code Online (Sandbox Code Playgroud)

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