Pytanie $ (document) .ready equivalent bez jQuery


Mam skrypt, który używa $(document).ready, ale nie używa niczego innego z jQuery. Chciałbym to rozjaśnić, usuwając zależność jQuery.

Jak mogę wdrożyć własne? $(document).ready funkcjonalność bez użycia jQuery? Wiem, że za pomocą window.onload nie będzie taki sam, jak window.onload uruchamia się po załadowaniu wszystkich obrazów, ramek itp.


1627
2018-04-28 21:51


pochodzenie


<body onload = "yourFunc ()"> jest zdecydowanie najlżejszy;) - cgp
... a także zdecydowanie nie ta sama funkcjonalność. - Joel Mueller
Tak jak ta odpowiedź stwierdza, jeśli wszystko, czego chcesz od jQuery jest $(document).ready, możesz łatwo rozwiązać ten problem, uruchamiając kod na samym dole strony zamiast u góry. HTML5Template używa tego dokładnego podejścia. - Blazemonger
Dlaczego nie skorzystać z DOMContentLoaded? To IE9 + caniuse.com/domcontentloaded  developer.mozilla.org/en-US/docs/Web/Events/DOMContentLoaded - Brock
Wezwałem swój telefon na końcu dokumentu i to rozwiązało mój problem. Po wywołaniu funkcji wszystko zostaje załadowane. - IgniteCoders


Odpowiedzi:


Istnieje zastępstwo oparte na standardach,DOMContentLoaded obsługiwany przez ponad 98% przeglądarek, chociaż nie IE8:

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

natywna funkcja jQuery jest znacznie bardziej skomplikowana niż tylko okno.onload, jak pokazano poniżej.

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

1053
2018-04-28 21:59



bindReady: github.com/jquery/jquery/blob/master/src/core.js - XP1
Rzeczywiste, działające, proste wdrożenie javascript tutaj, jeśli ktoś chce kodu, który może po prostu wstawić: stackoverflow.com/questions/9899372/... - jfriend00
Wydaje się, że kod gotowy jQuery DOM jest uproszczony: github.com/jquery/jquery/blob/master/src/core/ready.js - Jose Nobile
Myślę, że jesteśmy gotowi, aby przejść z IE8 ...;). Dzięki za link, @JoseNobile. - Con Antonakos
DOMContentLoaded nie będzie działać, jeśli skrypt zostanie załadowany później. Przygotowany dokument JQuery jest zawsze wykonywany. - Jared Insel


Edytować:

Oto opłacalny zamiennik gotowego produktu 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
});

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


Ponieważ zaakceptowana odpowiedź była bardzo daleka od kompletności, połączyłem funkcję "gotową", taką jak jQuery.ready() na podstawie źródła 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;
})();

Jak używać:

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

Nie jestem pewien, jak funkcjonalny jest ten kod, ale działał dobrze z moimi powierzchownymi testami. Trwało to dość długo, więc mam nadzieję, że Ty i inni możecie z tego skorzystać.

PS .: sugeruję kompilacja to.

Lub możesz użyć http://dustindiaz.com/smallest-domready-ever:

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

lub natywna funkcja, jeśli potrzebujesz tylko obsługi nowych przeglądarek (w przeciwieństwie do gotowego jQuery, to nie będzie działać, jeśli dodasz to po wczytaniu strony)

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

290
2017-08-13 20:52



O Boże. Będę myślał wiele razy przed usunięciem depresji jquery następnym razem. - Johnny_D
@Johnny_D Nie dodawaj zależności jQuery w pierwszej kolejności = Ból minął! - Frederik Krautwald
@FrederikKrautwald bez względu na to, co ludzie mówią, koncepcyjnie jQuery jest dobrą rzeczą, ponieważ interfejs DOM API jest bardzo rozdęty, gadatliwy i niekonsekwentny, po prostu życzę sobie, aby dostępna była wersja lite - Timo Huovinen
@TimoHuovinen Alternatywy: Zepto.js (9,1 kb), Snack.js (8,1 kb), $ dom (2,3 kb) i 140 Medley (0,5 kb). Edytować: Możesz również rzucić okiem na Endera. - Frederik Krautwald
@FrederikKrautwald $ dom brzmi jakbym chciał, ale nie jestem pewien, czy pasuje do rachunku. Zepto również wygląda obiecująco, dziękuję za udostępnienie! - Timo Huovinen


Trzy opcje:

  1. Gdyby script jest ostatnim znacznikiem ciała, DOM byłby gotowy przed uruchomieniem znacznika skryptu
  2. Kiedy DOM jest gotowy, "readyState" zmieni się na "complete"
  3. Umieść wszystko pod detektorem zdarzeń "DOMContentLoaded"

onreadystatechange

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

Źródło: MDN

DOMContentLoaded

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

Zaniepokojony przeglądarkami z epoki kamienia: Przejdź do kodu źródłowego jQuery i użyj ready funkcjonować. W takim przypadku nie parsujesz + wykonujesz całą bibliotekę, robisz tylko bardzo małą jej część.


184
2017-09-12 22:33



Ten drugi przykład jest dużo bardziej elegancki i zwięzły niż zaznaczone odpowiedzi. Dlaczego ten nie został oznaczony jako właściwy? - 0112
Nadal +1 dla rzeczy DOMContentLoaded, zrobił dokładnie to, co chciałem. - tripleee
onreadystatechange zrobił dla mnie sztuczkę ... potrzebował uruchomić jakiś skrypt po załadowaniu jQuery asynchronicznej. - Abram
Podobnie jak FYI, nr 1 nie jest całkowicie prawdziwy. Jest całkiem możliwe, że skrypt na końcu strony wczytuje się przed zakończeniem DOM. Właśnie dlatego słuchacze są lepsi. Słuchają, kiedy przeglądarka jest zakończona. Umieszczenie go na końcu przekreśla palcami, że ładowanie skryptu jest wolniejsze, niż przeglądarka może wyrenderować. - Machavity
ten wariant będzie działał również, gdy dokument jest już załadowany, proszę zaktualizować odpowiedź (imo best), jeśli potrafisz: if (document.readyState == "complete") {init (); } else {document.onreadystatechange = function () {if (document.readyState == 'complete') {init (); }}} - ZPiDER


Umieść swoje <script>/*JavaScript code*/</script> dobrze przed zamknięciem  </body> etykietka.

Prawdą jest, że może to nie odpowiadać wszystkim celom, ponieważ wymaga zmiany pliku HTML, a nie tylko robienia czegoś w pliku JavaScript a la document.ready, ale wciąż ...


81
2017-12-07 16:46



Wydaje mi się, że były problemy ze zgodnością, ponieważ strona nie jest jeszcze gotowa, nie można tego zrobić w tych i tych przeglądarkach. Niestety nie pamiętam jaśniej. Niemniej jednak +1 za sposób, który jest wystarczająco blisko w 99% wszystkich przypadków (i sugerowany przez Yahoo!). - Boldewyn
W rzeczywistości umieszczenie elementu skryptu na dole strony jest niemal idealnym rozwiązaniem. Działa w różnych przeglądarkach i symuluje document.ready perfect. Jedyną wadą jest to, że jest on (nieco) bardziej natarczywy niż użycie jakiegoś inteligentnego kodu, będziesz musiał poprosić użytkownika skryptu, który tworzysz, o dodanie dodatkowego fragmentu skryptu, aby wywołać twoją funkcję ready lub init. - Stijn de Witt
@StijndeWitt - Co masz na myśli mówiąc o wywołaniu funkcji init? Skrypt, który używa document.ready nie potrzebuje innego kodu klienta, aby go wywołać, jest samodzielny, a równoważny z tym, w którym kod jest zawarty na końcu ciała, może również być samodzielny i nie wymagać również innego kodu, aby go wywołać. - nnnnnn
Dlaczego nie umieścić skryptu po zamykający tag ciała i przed zamknięciem </html> etykietka? - Charles Holbrow


Rozwiązanie dla biednych ludzi:

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

checkLoad();  

Zobacz Fiddle

Dodano ten, nieco lepszy, jak sądzę, własny zakres i nierekurencyjny

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

Zobacz Fiddle


67
2017-08-04 18:13



@PhilipLangford Lub po prostu umieść go w środku setInterval i całkowicie usunąć rekursję. - Alex W
@Raveren, hmm masz rację, jestem prawie pewien, że testowałem to, kiedy to opublikowałem. tak czy inaczej, stało się jeszcze prostsze, teraz funkcja zostaje po prostu wywołana, bez pakowania. - Jakob Sternberg
To nie jest sexy. Przepraszam. Używanie timerów / interwałów do wykrywania rzeczy może "zadziałać", ale jeśli będziesz programować w ten sposób, każdy większy projekt warty swojej soli będzie nosił nurkowanie. Nie hakuj razem takich rzeczy. Zrób to dobrze. Proszę. Ten rodzaj kodu szkodzi ekosystemowi programistycznemu, ponieważ istnieje lepsze rozwiązanie, a Ty WIESZ. - dudewad
Myślę, że ta odpowiedź jest znacznie bliższa dustindiaz.com/smallest-domready-ever Poprawiłem skrypt: jsfiddle.net/iegik/PT7x9 - iegik
@ReidBlomquist Tak, i jest to "zły" sposób, i to właśnie wskazuję (choć trochę nieugięty, wiem). Można powiedzieć, że robiąc to źle, w jakiś sposób "pomaga" ekosystemowi, ale problem polega na tym, że liczba złego kodu, który ludzie biorą za "dobry" kod, ponieważ nie mają doświadczenia, aby wiedzieć lepiej NIE pomaga ekosystemowi, ponieważ wtedy będą oni brali ten zły kod i wdrażają go w rzeczywiste rozwiązanie architektoniczne do produkcji. Sądzę więc, że będziemy musieli po prostu różnić zdanie na temat tego "błędu". - dudewad


Używam tego:

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

Uwaga: Działa to prawdopodobnie tylko w nowszych przeglądarkach, zwłaszcza tych: http://caniuse.com/#feat=domcontentloaded


31
2017-12-23 19:14



IE9 i powyżej faktycznie - Pascalius


Naprawdę, jeśli ci na tym zależy Internet Explorer 9+ tylko ten kod wystarczyłby do zastąpienia jQuery.ready:

    document.addEventListener("DOMContentLoaded", callback);

Jeśli się martwisz Internet Explorer 6 i kilka naprawdę dziwnych i rzadkich przeglądarek, to zadziała:

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

19
2017-11-07 07:45





To pytanie zostało zadane dość dawno temu. Dla każdego, kto właśnie zobaczył to pytanie, jest teraz strona o nazwie "może nie potrzebujesz jquery"  który rozkłada - przez wymagany poziom wsparcia IE - całą funkcjonalność jquery i zapewnia kilka alternatywnych, mniejszych bibliotek.

Gotowy skrypt dokumentu IE8 według możesz nie potrzebować 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();
        });
}

15
2018-02-16 14:15



Zastanawiam się, dlaczego 'onreadystatechange' jest konieczne, a nie document.attachEvent('onload', fn); - Luke