Co to jest równoważny nie-jQuery '$ (dokument) .ready ()'?

444

Czym jest ekwiwalent inny niż jQuery $(document).ready()?

TIMEX
źródło
4
Jeśli chcesz odtworzyć $(document).ready()zdarzenie jQuery bez użycia biblioteki, spójrz na to: stackoverflow.com/questions/1795089/…
CMS
@OP: sprawdź stronę 89 technik Pro JavaScript, aby zapoznać się z waniliową implementacją JavaScript $(document).ready()- books.google.com/… . Wykorzystuje również addEventabstrakcję wiążącą zdarzenia napisaną przez Deana Edwardsa, której kod znajduje się również w książce :)
Russ Cam
2
możliwy duplikat $ (dokumentu). już ekwiwalent bez jQuery
Qantas 94 Heavy

Odpowiedzi:

73

Zaletą $(document).ready()jest to, że wcześniej strzela window.onload. Funkcja ładowania czeka, aż wszystko zostanie załadowane, w tym zasoby zewnętrzne i obrazy. $(document).ready, jednak uruchamia się, gdy drzewo DOM jest gotowe i można nim manipulować. Jeśli chcesz uzyskać gotową DOM, bez jQuery, możesz zalogować się do tej biblioteki. Ktoś wydobył tylko readyczęść z jQuery. Jest ładny i mały i może się przydać:

już w Google Code

Doug Neiner
źródło
4
Sieć kodów DomReady! przez @CMS na github: github.com/cms/domready/network
Kzqai
45
To nie odpowiada na pytanie ani nie pokazuje kodu innego niż jQuery. Skąd tyle głosów poparcia?
Daniel W.
3
@DanielW. Ponieważ jest to proste i praktyczne. Większość z nas przybyła tutaj, szukając sposobu, aby upewnić się, że DOM jest gotowy do użycia przez kod javascript.
abarazal
Tak, ale niektórzy z nas przyjechali tu po prawdziwą odpowiedź.
Slbox
614

Działa to doskonale, od ECMA

document.addEventListener("DOMContentLoaded", function() {
  // code...
});

window.onloadNie równa się JQuery $(document).readybo $(document).readytylko czeka na drzewie DOM whilewindow.onload sprawdzić wszystkie elementy, w tym aktywa zagraniczne i obrazów.

EDYCJA : Dodano IE8 i starszy odpowiednik, dzięki obserwacji Jana Derka . Możesz przeczytać źródło tego kodu w MDN pod tym linkiem :

// alternative to DOMContentLoaded
document.onreadystatechange = function () {
    if (document.readyState == "interactive") {
        // Initialize your application or run some code.
    }
}

Istnieją inne opcje oprócz "interactive". Zobacz link MDN, aby uzyskać szczegółowe informacje.

sospedra
źródło
Zgadzam się z Benjaminem. Nie możesz po prostu użyć attachEvent. Np. W Chrome dostajesz: Uncaught TypeError: document.attachEvent nie jest funkcją. Skorzystaj z połączonej odpowiedzi Jana Derk.
Manuel Arwed Schmidt
9
Co się stanie, jeśli dokument został już załadowany po wywołaniu tego skryptu? Nic się nie wydarzy :(
oriadam
8
@Deerloper Nope, właśnie wypróbowałem to na konsoli Chrome - nic się nie stało: document.addEventListener("DOMContentLoaded",function(){console.log(123)})spróbuj teraz
oriadam
2
Obsługa DOMContentLoaded w przeglądarkach: caniuse.com/domcontentloaded
Guillaume Husta
1
@elliottregan to prawda. Usuwam komentarz, aby uniknąć zanieczyszczenia tego wątku. Sugeruję, abyście wszyscy zrobili to samo :) I jeśli to konieczne, pozwólcie jednemu komentarzowi wskazać komentarz w razie potrzeby. Ponieważ jest to dodatkowe, ponieważ wykracza poza pytania OC
sospedra,
43

Mała rzecz, którą złożyłem

domready.js

(function(exports, d) {
  function domReady(fn, context) {

    function onReady(event) {
      d.removeEventListener("DOMContentLoaded", onReady);
      fn.call(context || exports, event);
    }

    function onReadyIe(event) {
      if (d.readyState === "complete") {
        d.detachEvent("onreadystatechange", onReadyIe);
        fn.call(context || exports, event);
      }
    }

    d.addEventListener && d.addEventListener("DOMContentLoaded", onReady) ||
    d.attachEvent      && d.attachEvent("onreadystatechange", onReadyIe);
  }

  exports.domReady = domReady;
})(window, document);

Jak tego użyć

<script src="domready.js"></script>
<script>
  domReady(function(event) {
    alert("dom is ready!");
  });
</script>

Możesz także zmienić kontekst, w którym działa wywołanie zwrotne, przekazując drugi argument

function init(event) {
  alert("check the console");
  this.log(event);
}

domReady(init, console);
Dziękuję Ci
źródło
2
Dziękuję Ci. Podoba mi się fakt, że jest kompatybilny wstecz. Posuwanie się naprzód nie oznacza po prostu pozostawienia mniej szczęśliwych ludzi. Brak możliwości korzystania z nowoczesnej przeglądarki (z jakiegokolwiek powodu) jest niefortunny ...
CO
28

Teraz, gdy jest rok 2018, oto szybka i prosta metoda.

Spowoduje to dodanie detektora zdarzeń, ale jeśli został już uruchomiony, sprawdzimy, czy domena jest w stanie gotowości lub czy jest kompletna. Może to zostać uruchomione przed lub po zakończeniu ładowania zasobów podrzędnych (obrazy, arkusze stylów, ramki itp.).

function domReady(fn) {
  // If we're early to the party
  document.addEventListener("DOMContentLoaded", fn);
  // If late; I mean on time.
  if (document.readyState === "interactive" || document.readyState === "complete" ) {
    fn();
  }
}

domReady(() => console.log("DOM is ready, come and get it!"));

Dodatkowe odczyty


Aktualizacja

Oto kilka szybkich pomocników narzędziowych, korzystających ze standardowego importu i eksportu ES6, które napisałem i które zawierają także TypeScript. Może uda mi się zrobić z nich szybką bibliotekę, którą można zainstalować w projektach jako zależność.

JavaScript

export const domReady = (callBack) => {
  if (document.readyState === "loading") {
    document.addEventListener('DOMContentLoaded', callBack);
  }
  else {
    callBack();
  }
}

export const windowReady = (callBack) => {
  if (document.readyState === 'complete') {
    callBack();
  }
  else {
    window.addEventListener('load', callBack);
  }
}

Maszynopis

export const domReady = (callBack: () => void) => {
  if (document.readyState === "loading") {
    document.addEventListener('DOMContentLoaded', callBack);
  }
  else {
    callBack();
  }
}

export const windowReady = (callBack: () => void) => {
  if (document.readyState === 'complete') {
    callBack();
  }
  else {
    window.addEventListener('load', callBack);
  }
}

Obietnice

export const domReady = new Promise(resolve => {
  if (document.readyState === "loading") {
    document.addEventListener('DOMContentLoaded', resolve);
  }
  else {
    resolve();
  }
});

export const windowReady = new Promise(resolve => {
  if (document.readyState === 'complete') {
    resolve();
  }
  else {
    window.addEventListener('load', resolve);
  }
});
CTS_AE
źródło
16

Według http://youmightnotneedjquery.com/#ready jest to miły zamiennik, który nadal działa z 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();
    });
  }
}

// test
window.ready(function() {
    alert('it works');
});

ulepszenia : osobiście sprawdziłbym również, czy typ funkcji fnjest funkcją. I jak sugeruje @elliottregan , usuń detektor zdarzeń po użyciu.

Powodem, dla którego odpowiadam na to pytanie późno, jest to, że szukałem tej odpowiedzi, ale nie mogłem jej tutaj znaleźć. I myślę, że to najlepsze rozwiązanie.

online Thomas
źródło
1
Tak, to moim zdaniem najlepsza odpowiedź. Łatwy do odczytania i wykonuje kod, nawet jeśli DOM jest już załadowany. Jedyne, co chciałbym dodać, to usunąć detektora zdarzeń po uruchomieniu zdarzenia.
elliottregan
14

Istnieje zastąpienie oparte na standardach, DOMContentLoaded, które jest obsługiwane przez ponad 90% + przeglądarek, ale nie IE8 (więc poniżej użycia kodu przez JQuery do obsługi przeglądarki) :

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 );
}
Zigri2612
źródło
1
Nowe jQuery porzuciło obsługę starszych przeglądarek, a teraz mają one tylko DOMContentLoadedi loadzdarzenia addEventListener, a po pierwsze, ogień usuwa oba nasłuchiwania, więc nie uruchamia się dwa razy.
jcubic
8

W zwykłym waniliowym JavaScript, bez bibliotek? To błąd. $jest po prostu identyfikatorem i jest niezdefiniowany, chyba że go zdefiniujesz.

jQuery definiuje $jako swój własny „obiekt wszystkiego” (znany również jako, jQuerydzięki czemu można go używać bez konfliktu z innymi bibliotekami). Jeśli nie używasz jQuery (lub innej biblioteki, która go definiuje), to $nie zostanie zdefiniowane.

A może pytasz, jaki jest odpowiednik zwykłego JavaScript? W takim przypadku prawdopodobnie chcesz window.onload, co nie jest dokładnie równoważne, ale jest najszybszym i najłatwiejszym sposobem, aby zbliżyć się do tego samego efektu w waniliowym JavaScript.

Brian Campbell
źródło
39
Dla wielu downvoters tej odpowiedzi (i pozostałych poniżej): kiedy pytanie zostało zadane, było po prostu: „Co to jest $ (dokument) .ready () w javascript? Nie jquery. Co to jest?” Wyglądało na to, że pyta, co to znaczy w zwykłym waniliowym JavaScript bez załadowanego jQuery. W mojej odpowiedzi próbowałem odpowiedzieć na to pytanie, a także udzielić najbliższej łatwej odpowiedzi dla zwykłego waniliowego JavaScript bez jQuery lub innych bibliotek, na wypadek gdyby to miał na myśli. Zauważ, że cały dodatkowy kontekst został dodany przez inne osoby zgadujące, o co pytanie, a nie oryginalny plakat.
Brian Campbell,
5

Najłatwiejszym sposobem w najnowszych przeglądarkach byłoby użycie odpowiednich GlobalEventHandlers , onDOMContentLoaded , onload , onloadeddata (...)

onDOMContentLoaded = (function(){ console.log("DOM ready!") })()

onload = (function(){ console.log("Page fully loaded!") })()

onloadeddata = (function(){ console.log("Data loaded!") })()

Zdarzenie DOMContentLoaded jest uruchamiane, gdy początkowy dokument HTML został całkowicie załadowany i przeanalizowany, bez oczekiwania na zakończenie ładowania arkuszy stylów, obrazów i podramek. Zupełnie inne ładowanie zdarzeń powinno być używane tylko do wykrywania w pełni załadowanej strony. Bardzo popularnym błędem jest użycie obciążenia, w którym DOMContentLoaded byłby znacznie bardziej odpowiedni, więc bądź ostrożny.

https://developer.mozilla.org/en-US/docs/Web/Events/DOMContentLoaded

Użyta funkcja jest IIFE, bardzo przydatna w tym przypadku, ponieważ wyzwala się, gdy jest gotowa:

https://en.wikipedia.org/wiki/Immed natychmiast-invoked_function_expression

Oczywiście bardziej odpowiednie jest umieszczenie go na końcu każdego skryptu.

W ES6 możemy również napisać go jako funkcję strzałki:

onload = (() => { console.log("ES6 page fully loaded!") })()

Najlepiej jest użyć elementów DOM, możemy poczekać, aż dowolna zmienna będzie gotowa, która wyzwoli IIFE ze strzałką.

Zachowanie będzie takie samo, ale przy mniejszym wpływie na pamięć.

footer = (() => { console.log("Footer loaded!") })()
<div id="footer">

W wielu przypadkach obiekt dokumentu jest również wyzwalany, gdy jest gotowy , przynajmniej w mojej przeglądarce. Składnia jest wtedy bardzo ładna, ale wymaga dalszych testów zgodności.

document=(()=>{    /*Ready*/   })()
NVRM
źródło
Czy wyzwalacz IIFE przed zakończeniem DOM może ładować elementy po nim?
CTS_AE
Jasne, to tylko funkcja, anonimowa funkcja w zamknięciu.
NVRM,
0

Body onLoad może być również alternatywą:

<html>
<head><title>Body onLoad Exmaple</title>

<script type="text/javascript">
    function window_onload() {
        //do something
    }
</script>

</head>
<body onLoad="window_onload()">

</body>
</html>
joan16v
źródło