$ (dokument). już ekwiwalent bez jQuery

2016

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łasną $(document).readyfunkcjonalność bez korzystania z jQuery? Wiem, że używanie window.onloadnie będzie takie samo, jak window.onloadpożary po załadowaniu wszystkich zdjęć, ramek itp.

FlySwat
źródło
296
... a także zdecydowanie nie ta sama funkcjonalność.
Joel Mueller
40
Jak wynika z tej odpowiedzi , jeśli wszystko, czego potrzebujesz od jQuery $(document).ready, możesz łatwo rozwiązać ten problem, uruchamiając kod na samym dole strony zamiast na górze. HTML5Boilerplate stosuje to dokładne podejście.
Blazemonger,
3
Dlaczego nie skorzystać z DOMContentLoaded? To IE9 + caniuse.com/domcontentloaded developer.mozilla.org/en-US/docs/Web/Events/DOMContentLoaded
Brock
W końcu zatelefonowałem do dokumentu i to rozwiązało mój problem. Po wywołaniu funkcji wszystko jest ładowane.
IgniteCoders

Odpowiedzi:

1440

Istnieje zastąpienie oparte na standardach, DOMContentLoadedktóre jest obsługiwane przez ponad 98% przeglądarek , ale nie IE8:

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

Natywna funkcja jQuery jest o wiele bardziej skomplikowana niż tylko window.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 );
}
Chad Grant
źródło
19
Rzeczywista działająca implementacja zwykłego javascript tutaj, jeśli ktoś chce kodu, może po prostu wpaść: stackoverflow.com/questions/9899372/…
jfriend00
4
Wygląda na to, że gotowy kod jQuery DOM jest uproszczony: github.com/jquery/jquery/blob/master/src/core/ready.js
Jose Nobile
2
@JoseNobile, ponieważ porzucili obsługę starszych przeglądarek
huysentruitw
16
Myślę, że wszyscy jesteśmy gotowi na przejście z IE8 ...;). Dzięki za link, @JoseNobile.
Con Antonakos,
13
DOMContentLoaded nie będzie działać, jeśli skrypt zostanie później załadowany. Dokument JQuery gotowy jest zawsze wykonywany.
Jared Insel
343

Edytować:

Oto realny zamiennik jQuery gotowy

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

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

Kolejna dobra funkcja domReady tutaj pochodzi z https://stackoverflow.com/a/9899701/175071


Ponieważ zaakceptowana odpowiedź była daleka od ukończenia, 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. Zajęło to sporo czasu, więc mam nadzieję, że Ty i inni możecie z tego skorzystać.

PS .: Sugeruję kompilację .

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 funkcję natywną, jeśli potrzebujesz obsługiwać tylko nowe przeglądarki (w przeciwieństwie do jQuery ready, nie uruchomi się, jeśli dodasz to po załadowaniu strony)

document.addEventListener('DOMContentLoaded',function(){/*fun code to run*/})
Timo Huovinen
źródło
14
@TimoHuovinen Alternatywy: Zepto.js (9,1 kb), Snack.js (8,1 kb), $ dom (2,3 kb) i 140 Medley (0,5 kb). Edycja: Możesz także spojrzeć na Endera.
Frederik Krautwald
2
@FrederikKrautwald $ dom brzmi jak chciałbym, ale nie jestem pewien, czy pasuje do rachunku. Zepto również wygląda naprawdę obiecująco, dziękuję za udostępnienie!
Timo Huovinen
@TimoHuovinen Jeśli nie spojrzałeś na Endera, zdecydowanie powinieneś rzucić okiem, enderjs.com .
Frederik Krautwald
2
@Timo Huovinen: Twoje pytanie jest naprawdę, bardzo szerokie! Kiedy jQuery zostało utworzone, zawierało wiele problemów z różnymi przeglądarkami generowanych przez przeglądarki, które są dziś mniej znaczące. Dzisiaj „tylko javascript” jest łatwiejsze niż było. W tej chwili stworzenie „dużego skompresowanego pliku o wielkości 20 KB, który zawiera wszystko” z pewnością było dobrym pomysłem z wielu powodów, dla których wolę nie wymieniać ich wszystkich.
dotpush,
1
Nie lubie tego Jeśli ludzie wolą tę odpowiedź, zadaj sobie pytanie, dlaczego chcesz porzucić jQuery. Jest to trochę bezcelowe, jeśli zamierzasz wyodrębnić dokładnie tę samą funkcjonalność z całym powrotem do pakietu w przeglądarce. Czy nie o to chodzi przede wszystkim w unikaniu jQuery?
Phil
208

Trzy opcje:

  1. Jeśli scriptjest ostatnim znacznikiem treści, DOM byłby gotowy przed wykonaniem znacznika skryptu
  2. Gdy DOM będzie gotowy, „readyState” zmieni się na „ukończone”
  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żyjreadyfunkcji. W takim przypadku nie parsujesz + nie wykonujesz całej biblioteki, a jedynie niewielką jej część.

Jhankar Mahbub
źródło
3
Ten drugi przykład jest znacznie bardziej elegancki i zwięzły niż zaznaczone odpowiedzi. Dlaczego ten nie został oznaczony jako poprawny?
0112
2
Wciąż +1 dla elementu DOMContentLoaded, zrobił dokładnie to, czego chciałem.
tripleee
1
onreadystatechange zrobił dla mnie lewę ... musiał uruchomić skrypt po wczytaniu asynchronicznej jquery.
Abram
2
Podobnie jak w przypadku FYI, nr 1 nie jest do końca prawdą. Jest całkiem możliwe, że skrypt na końcu strony zostanie załadowany przed ukończeniem DOM. Dlatego słuchacze są lepsi. Słuchają, kiedy przeglądarka jest skończona. Umieszczenie go na końcu oznacza, że ​​ładowanie skryptu było wolniejsze niż przeglądarka może renderować.
Machavity
1
ten wariant będzie działał również po zakończeniu ładowania dokumentu, zaktualizuj swoją odpowiedź (imo best), jeśli możesz: if (document.readyState == 'complete') {init (); } else {document.onreadystatechange = function () {if (document.readyState == 'complete') {init (); }}}
ZPiDER
87

Umieść swoje <script>/*JavaScript code*/</script>prawo przed </body> tagiem zamykającym .

Trzeba przyznać, że może to nie pasować do wszystkich celów, ponieważ wymaga zmiany pliku HTML, a nie tylko zrobienia czegoś w pliku JavaScript document.ready, ale nadal ...

obrabować
źródło
Wydaje mi się, że wystąpiły problemy ze zgodnością, np. 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 dla sposobu, który jest wystarczająco blisko w 99% wszystkich przypadków (i sugerowane przez Yahoo!).
Boldewyn,
7
W rzeczywistości umieszczenie elementu skryptu na dole strony jest prawie idealnym rozwiązaniem. Działa w różnych przeglądarkach i symuluje document.ready perfect. Jedyną wadą jest to, że jest (nieco) bardziej natarczywy niż użycie jakiegoś inteligentnego kodu, będziesz musiał poprosić użytkownika tworzonego skryptu o dodanie dodatkowego fragmentu skryptu, aby wywołał twoją funkcję gotową lub init.
Stijn de Witt,
@StijndeWitt - Co masz na myśli mówiąc o konieczności wywołania funkcji init? Skrypt korzystający z document.ready nie potrzebuje innego kodu klienta do wywołania go, jest samowystarczalny, a odpowiednik tego, w którym kod znajduje się na końcu treści, może również być samowystarczalny i nie zawiera wymagają też innego kodu, aby to nazwać
nnnnnn
1
Dlaczego nie umieścić skryptu za tagiem zamykającym ciało, a przed </html>tagiem zamykającym ?
Charles Holbrow,
1
@CharlesHolbrow Chociaż wszystkie przeglądarki interpretują go poprawnie, jeśli chcesz, aby był prawidłowy HTML, htmltag powinien zawierać tylko headi body.
Alvaro Montoro,
66

Rozwiązanie biednego człowieka:

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

checkLoad();  

Zobacz skrzypce

Dodałem ten, nieco lepiej, chyba własny zakres i nie rekurencyjny

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

Zobacz skrzypce

Jakob Sternberg
źródło
8
@PhilipLangford Lub po prostu włóż go do setIntervali całkowicie usuń rekurencję.
Alex W
1
@Raveren, hmm masz rację, jestem pewien, że przetestowałem go, kiedy go opublikowałem. w każdym razie stało się to jeszcze prostsze, teraz funkcja właśnie się wywołuje, bez owijania.
Jakob Sternberg,
24
To nie jest seksowne. Nie. Przepraszam. Używanie timerów / interwałów do wykrywania rzeczy może „działać”, ale jeśli będziesz kontynuować programowanie w ten sposób, każdy większy projekt wart swojej soli pójdzie nurkować. Nie hakuj takich rzeczy razem. Zrób to dobrze. Proszę. Ten rodzaj kodu szkodzi ekosystemowi programistycznemu, ponieważ istnieje lepsze rozwiązanie i WIESZ.
dudewad
1
Myślę, że ta odpowiedź jest znacznie bliższa do dustindiaz.com/smallest-domready-ever Więc poprawiłem skrypt: jsfiddle.net/iegik/PT7x9
iegik
1
@ReidBlomquist Tak, i to jest „zły” sposób, i to właśnie wskazuję (choć trochę stanowczo, wiem). Można powiedzieć, że źle to robi w jakiś sposób „pomaga” ekosystemowi, ale problem polega na tym, że przy złej ilości kodu, który ludzie przyjmują za „dobry” kod, ponieważ nie mają doświadczenia, aby wiedzieć lepiej NIE pomaga ekosystemowi, ponieważ wtedy wezmą ten zły kod i zaimplementują go w rzeczywistym rozwiązaniu architektury produkcyjnej. Sądzę, że będziemy musieli się różnić poglądami na temat tego „błędu”.
dudewad
34

Używam tego:

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

Uwaga: prawdopodobnie działa to tylko w nowszych przeglądarkach, szczególnie tych: http://caniuse.com/#feat=domcontentloaded

Dustin Davis
źródło
13
IE9 i wyższe faktycznie
Pascalius
Działa to również świetnie w skryptach treści rozszerzenia Chrome, jeśli przechwytywałeś zdarzenie document_start lub document_idle.
Volomike 31.01.19
21

Naprawdę, jeśli zależy Ci tylko na Internet Explorerze 9+ , ten kod wystarczy, aby zastąpić jQuery.ready:

    document.addEventListener("DOMContentLoaded", callback);

Jeśli martwisz się o Internet Explorer 6 i niektóre naprawdę dziwne i rzadkie przeglądarki, zadziała to:

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();
        }
    }
},
Dan
źródło
18

To pytanie zostało zadane już dawno temu. Dla każdego, kto widzi to pytanie, jest teraz strona o nazwie „może nie potrzebujesz jquery”, która rozkłada - według wymaganego poziomu obsługi IE - całą funkcjonalność jquery i zapewnia alternatywne, mniejsze biblioteki.

Skrypt gotowy do dokumentu IE8 według ciebie może nie wymagać 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();
        });
}
chugadie
źródło
Zastanawiam się, dlaczego 'onreadystatechange'jest to konieczne, a niedocument.attachEvent('onload', fn);
Łukasz
13

Ostatnio używałem tego na stronie mobilnej. To jest uproszczona wersja Johna Resiga z „Pro JavaScript Techniques”. To zależy od 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;
})();
James
źródło
13
Uważaj na ten kod. NIE jest to równowartość $ (dokumentu) .ready. Ten kod wyzwala oddzwonienie, gdy document.body jest gotowy, co nie gwarantuje pełnego załadowania DOM.
Karolis
12

Wiele przeglądarek (także stare przeglądarki) i proste rozwiązanie:

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

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

Pokazuje alert w jsfiddle

Paweł
źródło
Z wyjątkiem sytuacji, gdy załadowanie DOM zajmuje więcej niż 30 ms, kod nie będzie działać.
Quelklef
1
@Quelklef that setInterval not setTimeout
Paweł
11

Odpowiedź jQuery była dla mnie bardzo przydatna. Przy odrobinie refraktu dobrze pasowało do moich potrzeb. Mam nadzieję, że pomoże to komukolwiek innemu.

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 )
}
Miere
źródło
w niektórych przeglądarkach removeListenertrzeba będzie wywoływać z dokumentem jako kontekstem, tj. removeListener.call(document, ...
Ron
9

Oto najmniejszy fragment kodu do testowania DOM gotowy, który działa we wszystkich przeglądarkach (nawet IE 8):

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

Zobacz tę odpowiedź .

Antara Roy
źródło
6

Po prostu dodaj to na dole strony HTML ...

<script>
    Your_Function();
</script>

Ponieważ dokumenty HTML są analizowane od góry do dołu.

davefrassoni
źródło
7
Skąd wiesz, że DOM jest budowany, gdy ten kod jest wykonywany? W tym załadowany i przeanalizowany CSS? Interfejs API przeglądarki DOMContentLoaded jest do tego przeznaczony.
Dan.
To naprawdę zależy od tego, co chce zrobić z js. Jeśli naprawdę musi coś wykonać po zakończeniu strony, czy nie.
davefrassoni
5

Warto przyjrzeć się w Rock Solid addEvent () i http://www.braksator.com/how-to-make-your-own-jquery .

Oto kod na wypadek awarii strony

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");});
Ben
źródło
Drugi link jest zepsuty.
Peter Mortensen
4

Ten kod przeglądarki wywoła funkcję, gdy DOM będzie gotowy:

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

Oto jak to działa:

  1. Pierwszy wiersz domReadywywołuje toStringmetodę funkcji, aby uzyskać ciąg reprezentujący przekazywaną funkcję i zawija ją w wyrażenie, które natychmiast wywołuje funkcję.
  2. Reszta domReadytworzy element skryptu z wyrażeniem i dołącza go do bodydokumentu.
  3. Przeglądarka uruchamia tagi skryptowe dołączane bodypo przygotowaniu modelu DOM.

Na przykład, jeśli to zrobisz: domReady(function(){alert();});do bodyelementu zostaną dodane następujące elementy:

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

Pamiętaj, że działa to tylko w przypadku funkcji zdefiniowanych przez użytkownika. Następujące elementy nie będą działać:domReady(alert);

Max Heiber
źródło
3

Co powiesz na to rozwiązanie?

// 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();
};
mikrofon
źródło
3
Możesz użyć addEventListener na oknie z „load”. Detektory są wykonywane jeden po drugim i nie wymagają ręcznego tworzenia łańcuchów.
Zaffy,
1
Ale obciążenie jest inne niż gotowe. „Ładowanie” następuje nawet zanim dokument jest „gotowy”. Gotowy dokument ma załadowany DOM, załadowane okno niekoniecznie ma gotowy DOM. Dobra odpowiedź
Mzn
1
@Mzn: Myślę, że to wstecz. Myślę, że dokument jest gotowy przed zdarzeniem ładowania okna. „Zasadniczo nie trzeba czekać na pełne załadowanie wszystkich obrazów. Jeśli kod można wykonać wcześniej, zwykle najlepiej jest umieścić go w module obsługi wysłanym do metody .ready ().” ( api.jquery.com/load-event )
Tyler Rick
spowoduje to zastąpienie pozostałych zdarzeń window.onload na stronie i spowoduje problemy. powinien dodać zdarzenie na istniejącym.
Teoman shipahi
Zdarzenie ładowania może nastąpić za późno. Używanie go jest bolesne, gdy zależy od zewnętrznych plików js / obrazów innych firm ... Nieodpowiadający serwer, którego nie kontrolujesz i wszystko zawiedzie. Korzystanie z DOMContentLoaded to nie tylko optymalizacja, ale także bezpieczniejsze!
dotpush,
3

Zawsze dobrze jest używać ekwiwalentów JavaScript w porównaniu do jQuery. Jednym z powodów jest mniejsza biblioteka, na której można polegać, i są one znacznie szybsze niż odpowiedniki jQuery.

Jednym z fantastycznych odniesień do odpowiedników jQuery jest http://youmightnotneedjquery.com/ .

Jeśli chodzi o twoje pytanie, wziąłem poniższy kod z powyższego linku :) Jedynym zastrzeżeniem jest to, że działa tylko z Internet Explorerem 9 i nowszymi.

function ready(fn) {
    if (document.readyState != 'loading') {
        fn();
    }
    else {
        document.addEventListener('DOMContentLoaded', fn);
    }
}
Vatsal
źródło
3

Najbardziej minimalna i 100% działająca

Wybrałem odpowiedź od PlainJS i działa ona dla mnie dobrze. Rozszerza się, DOMContentLoadedaby można go było akceptować we wszystkich przeglądarkach.


Ta funkcja jest odpowiednikiem metody jQuery $(document).ready():

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

Jednak w przeciwieństwie do jQuery, kod ten będzie działał poprawnie tylko w nowoczesnych przeglądarkach (IE> 8) i nie będzie tak, jeśli dokument jest już renderowany w momencie wstawienia skryptu (np. Przez Ajax). Dlatego musimy nieco to rozszerzyć:

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

Obejmuje to zasadniczo wszystkie możliwości i jest realnym zamiennikiem pomocnika jQuery.

Shivam Sharma
źródło
2

Znaleźliśmy naszą szybką i brudną implementację w różnych przeglądarkach, która może załatwić sprawę w najprostszych przypadkach przy minimalnej implementacji:

window.onReady = function onReady(fn){
    document.body ? fn() : setTimeout(function(){ onReady(fn);},50);
};
malko
źródło
co jest doc.body!
Nabi KAZ
2

Przedstawione tutaj rozwiązania setTimeout / setInterval będą działać tylko w określonych okolicznościach.

Problem pojawia się zwłaszcza w starszych wersjach Internet Explorera do 8.

Zmienne wpływające na sukces tych rozwiązań setTimeout / setInterval to:

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

oryginalny (rodzimy kod JavaScript) rozwiązujący ten konkretny problem znajduje się tutaj:

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

jest to kod, z którego zespół jQuery zbudował swoją implementację.

Diego Perini
źródło
1

Oto, czego używam, jest szybki i obejmuje wszystkie podstawy, które myślę; działa na wszystko oprócz IE <9.

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

Wydaje się, że obejmuje to wszystkie przypadki:

  • uruchamia się natychmiast, jeśli DOM jest już gotowy (jeśli DOM nie „ładuje się”, ale „interaktywnie” lub „kończy”)
  • jeśli DOM nadal się ładuje, konfiguruje detektor zdarzeń, gdy DOM jest dostępny (interaktywny).

Zdarzenie DOMContentLoaded jest dostępne w IE9 i wszystkim innym, więc osobiście uważam, że można z niego korzystać. Przepisz deklarację funkcji strzałki do zwykłej funkcji anonimowej, jeśli nie transponujesz kodu z ES2015 na ES5.

Jeśli chcesz poczekać, aż wszystkie zasoby zostaną załadowane, wszystkie wyświetlane obrazy itp., Użyj zamiast tego window.onload.

Olemak
źródło
1

Jeśli nie musisz obsługiwać bardzo starych przeglądarek, możesz to zrobić nawet wtedy, gdy zewnętrzny skrypt jest załadowany atrybutem asynchronicznym :

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");
});
użytkownik4617883
źródło
0

W przypadku IE9 +:

function ready(fn) {
  if (document.readyState != 'loading'){
    fn();
  } else {
    document.addEventListener('DOMContentLoaded', fn);
  }
}
Joaquinglezsantos
źródło
0

Jeśli ładujesz jQuery u dołu BODY, ale masz problem z kodem, który wypisuje jQuery (<func>) lub jQuery (dokument) .ready (<func>), sprawdź jqShim na Github.

Zamiast odtwarzać własną funkcję przygotowywania dokumentu, po prostu trzyma się funkcji, dopóki jQuery nie będzie dostępny, a następnie przejdzie do jQuery zgodnie z oczekiwaniami. Przesunięcie jQuery na dół treści polega na przyspieszeniu wczytywania strony, a nadal możesz to zrobić, wstawiając plik jqShim.min.js w nagłówek szablonu.

Skończyło się na pisaniu tego kodu, aby przenieść wszystkie skrypty w WordPressie do stopki, a ten kod shim teraz znajduje się bezpośrednio w nagłówku.

Matt Pileggi
źródło
0

Spróbuj tego:

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

źródło
Lol, zadzwonisz dwa razy
Andrew
0
function onDocReady(fn){ 
    $d.readyState!=="loading" ? fn():document.addEventListener('DOMContentLoaded',fn);
}

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

onDocReady zapewnia wywołanie zwrotne, gdy domena HTML jest gotowa do pełnego dostępu / parsowania / manipulacji.

onWinLoad zapewnia oddzwonienie, gdy wszystko się załaduje (obrazy itp.)

  • Funkcje te można wywoływać w dowolnym momencie.
  • Obsługuje wielu „słuchaczy”.
  • Będzie działać w dowolnej przeglądarce.
Jakob Sternberg
źródło
0
(function(f){
  if(document.readyState != "loading") f();
  else document.addEventListener("DOMContentLoaded", f);
})(function(){
  console.log("The Document is ready");
});
Dustin Poissant
źródło
Co to dodaje, że inne odpowiedzi nie?
dwjohnston
Używa zamkniętego zamknięcia (nie wypełnia globalnego zakresu „okna”), działa na wszystkich przeglądarkach i jest bardzo zwarta. Nie widzę innych podobnych odpowiedzi.
Dustin Poissant
Działa również nawet po załadowaniu DOM (podobnie jak jQuery.ready), czego większość z tych odpowiedzi nie robi.
Dustin Poissant
0

Większość waniliowych funkcji JS Ready NIE DOMContentLoadedbierze pod uwagę scenariusza, w którym moduł obsługi jest ustawiony po załadowaniu dokumentu - co oznacza, że ​​funkcja nigdy się nie uruchomi . Może się to zdarzyć, jeśli szukasz w DOMContentLoadedciąguasync skryptu zewnętrznego ( <script async src="file.js"></script>).

Poniższy kod sprawdza, DOMContentLoadedczy tylko dokument readyStatenie jest już interactivelubcomplete .

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

Jeśli chcesz również obsługiwać 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!
});
Zero
źródło
0

Po prostu używam:

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

I w przeciwieństwie document.addEventListener("DOMContentLoaded" //etcdo samej najwyższej odpowiedzi, działa już w IE9 - http://caniuse.com/#search=DOMContentLoaded wskazuje tylko tak niedawno, jak IE11.

Co ciekawe natknąłem się na to setTimeoutrozwiązanie w 2009 roku: czy sprawdzanie gotowości do nadmiaru DOM? , które prawdopodobnie można by sformułować nieco lepiej, ponieważ miałem na myśli „czy przesadą jest używanie bardziej skomplikowanych metod różnych frameworków do sprawdzania gotowości DOM”.

Moim najlepszym wytłumaczeniem, dlaczego ta technika działa, jest to, że po osiągnięciu skryptu z takim setTimeout DOM jest w trakcie analizy, więc wykonanie kodu w setTimeout zostaje odroczone do czasu zakończenia tej operacji.

Dexygen
źródło