Pur équivalent JavaScript du $jQuery.ready () - comment appeler une fonction lorsque la page/DOM est prête pour elle [dupliquer]

cette question a déjà une réponse ici:

  • $(document).équivalent prêt à l'emploi sans jQuery 32 réponses

OK, c'est peut-être juste une question idiote, mais je suis sûr qu'il y a plein d'autres personnes qui posent la même question de temps en temps. Moi, je veux juste assure-toi à 100% de toute façon. Avec jQuery nous connaissons tous le merveilleux

$('document').ready(function(){});

Cependant, disons que je veux exécuter une fonction qui est écrit en JavaScript standard avec pas de bibliothèque de sauvegarde, et que je veux lancer une fonction dès que la page est prête à gérer. Quelle est la bonne façon d'aborder cette question?

je sais que je peux le faire:

window.onload="myFunction()";

...ou je peux utiliser l'étiquette body :

<body onload="myFunction()">

...ou je peux même essayer au bas de la page, après tout, mais la fin body ou html tag:

<script type="text/javascript">
   myFunction();
</script>

Qu'est-ce qu'une méthode(ancienne/nouvelle) conforme à la norme cross-browser pour émettre une ou plusieurs fonctions d'une manière semblable à $.ready() de jQuery ?

948
demandé sur Peter Mortensen 2012-03-28 03:57:21

10 réponses

la chose la plus simple à faire en l'absence d'un framework qui fait toute la compatibilité cross-browser pour vous est de simplement mettre un appel à votre code à la fin du corps. Ceci est plus rapide à exécuter qu'un handler onload parce que cela attend seulement que le DOM soit prêt, pas que toutes les images soient chargées. Et, cela fonctionne dans tous les navigateurs.

<html>
<head>
</head>
<body>
Your HTML here

<script>
// self executing function here
(function() {
   // your page initialization code here
   // the DOM will be available here

})();
</script>
</body>
</html>

si vous ne voulez vraiment pas le faire de cette façon et que vous avez besoin de compatibilité entre navigateurs et que vous ne voulez pas pour attendre window.onload , alors vous devriez probablement aller voir comment un cadre comme jQuery implémente la méthode $(document).ready() . Il est assez impliqué selon les capacités du navigateur.

pour vous donner une petite idée de ce que fait jQuery (qui fonctionnera partout où la balise script est placée).

si supporté, il essaie le standard:

document.addEventListener('DOMContentLoaded', fn, false);

avec un repli vers:

window.addEventListener('load', fn, false )

ou pour les versions plus anciennes D'IE, il utilise:

document.attachEvent("onreadystatechange", fn);

avec un repli vers:

window.attachEvent("onload", fn);

et, il y a quelques solutions dans le chemin du code IE que je ne suis pas tout à fait, mais il semble que cela a quelque chose à voir avec les cadres.


voici un substitut complet au .ready() de jQuery écrit en javascript simple:

(function(funcName, baseObj) {
    // The public function name defaults to window.docReady
    // but you can pass in your own object and own function name and those will be used
    // if you want to put them in a different namespace
    funcName = funcName || "docReady";
    baseObj = baseObj || window;
    var readyList = [];
    var readyFired = false;
    var readyEventHandlersInstalled = false;

    // call this when the document is ready
    // this function protects itself against being called more than once
    function ready() {
        if (!readyFired) {
            // this must be set to true before we start calling callbacks
            readyFired = true;
            for (var i = 0; i < readyList.length; i++) {
                // if a callback here happens to add new ready handlers,
                // the docReady() function will see that it already fired
                // and will schedule the callback to run right after
                // this event loop finishes so all handlers will still execute
                // in order and no new ones will be added to the readyList
                // while we are processing the list
                readyList[i].fn.call(window, readyList[i].ctx);
            }
            // allow any closures held by these functions to free
            readyList = [];
        }
    }

    function readyStateChange() {
        if ( document.readyState === "complete" ) {
            ready();
        }
    }

    // This is the one public interface
    // docReady(fn, context);
    // the context argument is optional - if present, it will be passed
    // as an argument to the callback
    baseObj[funcName] = function(callback, context) {
        if (typeof callback !== "function") {
            throw new TypeError("callback for docReady(fn) must be a function");
        }
        // if ready has already fired, then just schedule the callback
        // to fire asynchronously, but right away
        if (readyFired) {
            setTimeout(function() {callback(context);}, 1);
            return;
        } else {
            // add the function and context to the list
            readyList.push({fn: callback, ctx: context});
        }
        // if document already ready to go, schedule the ready function to run
        if (document.readyState === "complete") {
            setTimeout(ready, 1);
        } else if (!readyEventHandlersInstalled) {
            // otherwise if we don't have event handlers installed, install them
            if (document.addEventListener) {
                // first choice is DOMContentLoaded event
                document.addEventListener("DOMContentLoaded", ready, false);
                // backup is window load event
                window.addEventListener("load", ready, false);
            } else {
                // must be IE
                document.attachEvent("onreadystatechange", readyStateChange);
                window.attachEvent("onload", ready);
            }
            readyEventHandlersInstalled = true;
        }
    }
})("docReady", window);

la dernière version du code est partagé publiquement sur GitHub à https://github.com/jfriend00/docReady

Utilisation:

// pass a function reference
docReady(fn);

// use an anonymous function
docReady(function() {
    // code here
});

// pass a function reference and a context
// the context will be passed to the function as the first argument
docReady(fn, context);

// use an anonymous function with a context
docReady(function(context) {
    // code here that can use the context argument that was passed to docReady
}, ctx);

ceci a été testé dans:

IE6 and up
Firefox 3.6 and up
Chrome 14 and up
Safari 5.1 and up
Opera 11.6 and up
Multiple iOS devices
Multiple Android devices

Travail de mise en œuvre et de tester lit: http://jsfiddle.net/jfriend00/YfD3C/


Voici un résumé de la façon dont il fonctionne:

  1. crée un IIFE (expression de fonction immédiatement invoquée) pour que nous puissions avoir des variables d'état non publiques.
  2. déclarer une fonction publique docReady(fn, context)
  3. lorsque docReady(fn, context) est appelé, vérifiez si le gestionnaire prêt a déjà tiré. Si c'est le cas, il suffit de programmer le callback nouvellement ajouté à fire juste après que ce thread de JS se termine avec setTimeout(fn, 1) .
  4. si le conducteur prêt n'a pas déjà tiré, puis ajouter ce nouveau rappel de la liste des rappels à être appelé plus tard.
  5. vérifiez si le document est déjà prêt. Si c'est le cas, exécutez tous les manipulateurs prêts.
  6. si nous n'avons pas encore installé les écouteurs d'événements pour savoir quand le document est prêt, alors installez-les maintenant.
  7. si document.addEventListener existe, alors installer des gestionnaires d'événements en utilisant .addEventListener() pour les deux événements "DOMContentLoaded" et "load" . La "charge" est une sauvegarde événement pour la sécurité et ne devrait pas être nécessaire.
  8. si document.addEventListener n'existe pas, alors installer des gestionnaires d'événements en utilisant .attachEvent() pour "onreadystatechange" et "onload" événements.
  9. dans l'événement onreadystatechange , vérifiez si le document.readyState === "complete" et si oui, appelez une fonction pour virer tous les manipulateurs prêts.
  10. dans tous les autres gestionnaires d'événements, appelez une fonction pour virer tous les gestionnaires prêts.
  11. dans le fonction pour appeler tous les gestionnaires prêts, Vérifiez une variable d'État pour voir si nous avons déjà tiré. Si nous avons, ne rien faire. Si nous n'avons pas encore été appelés, alors faites une boucle dans le tableau des fonctions prêtes et appelez chacune dans l'ordre où elles ont été ajoutées. Mettez un drapeau pour indiquer qu'ils ont tous été appelés de sorte qu'ils ne soient jamais exécutés plus d'une fois.
  12. effacer le tableau de fonction de sorte que les fermetures qu'ils pourraient être en utilisant peuvent être libérés.

Gestionnaires enregistrés avec docReady() sont garantis d'être tiré dans l'ordre où ils ont été enregistrés.

si vous appelez docReady(fn) après que le document est déjà prêt, l'appel sera programmé pour s'exécuter dès que le fil courant d'exécution se termine en utilisant setTimeout(fn, 1) . Cela permet au code appelant de toujours supposer qu'il s'agit de callbacks async qui seront appelés plus tard, même si plus tard est dès que le thread courant de JS se termine et préserve l'ordre d'appel.

1403
répondu jfriend00 2018-04-08 10:35:29

je voudrais mentionner quelques-uns des moyens possibles ici avec un pur tour javascript qui fonctionne à travers tous les navigateurs :

// with jQuery 
$(document).ready(function(){ /* ... */ });

// shorter jQuery version 
$(function(){ /* ... */ });

// without jQuery (doesn't work in older IEs)
document.addEventListener('DOMContentLoaded', function(){ 
    // your code goes here
}, false);

// and here's the trick (works everywhere)
function r(f){/in/.test(document.readyState)?setTimeout('r('+f+')',9):f()}
// use like
r(function(){
    alert('DOM Ready!');
});

le truc ici, comme expliqué par auteur original , est que nous vérifions le document .readyState propriété. Si elle contient la chaîne de caractères in (comme dans uninitialized et loading , les deux premiers États DOM ready out of 5) nous avons fixé un délai d'attente et vérifier de nouveau. Sinon, nous exécutons la fonction.

et voici le jsFiddle pour l'astuce qui fonctionne à travers tous les navigateurs.

merci à Tutorialzine pour avoir inclus ceci dans leur livre.

104
répondu Ram Patra 2016-11-04 05:18:30

Si vous faites des VANILLE plaine JavaScript sans jQuery, alors vous devez utiliser Internet Explorer 9 ou version ultérieure):

document.addEventListener("DOMContentLoaded", function(event) {
    // Your code to run since DOM is loaded and ready
});

ci-dessus est l'équivalent de jQuery .ready :

$(document).ready(function() {
    console.log("Ready!");
});

qui pourrait aussi être écrit en sténographie comme ceci, que jQuery exécutera après le prêt même se produit .

$(function() {
    console.log("ready!");
});

À NE PAS CONFONDRE avec ci-dessous (qui n'est pas destiné à être DOM prêt):

ne pas utiliser un IIFE comme ceci qui est auto-exécution:

 Example:

(function() {
   // Your page initialization code here  - WRONG
   // The DOM will be available here   - WRONG
})();

Ce IIFE ne sera PAS attendre pour votre DOM à charger. (Je parle même de la dernière version du navigateur Chrome!)

87
répondu Tom Stickel 2018-01-17 05:36:34

testé dans IE9, et les dernières Firefox et Chrome et également pris en charge dans IE8.

document.onreadystatechange = function () {
  var state = document.readyState;
  if (state == 'interactive') {
      init();
  } else if (state == 'complete') {
      initOnCompleteLoad();
  }
}​;

exemple: http://jsfiddle.net/electricvisions/Jacck /

mise à jour - version réutilisable

je viens de développer ce qui suit. C'est un équivalent plutôt simpliste de jQuery ou Dom prêt sans rétrocompatibilité. Il faut probablement le raffiner davantage. Testé dans le dernier versions de Chrome, Firefox et IE (10/11)et devrait fonctionner dans les navigateurs plus anciens commentés. Je vais mettre à jour si je trouve tous les problèmes.

window.readyHandlers = [];
window.ready = function ready(handler) {
  window.readyHandlers.push(handler);
  handleState();
};

window.handleState = function handleState () {
  if (['interactive', 'complete'].indexOf(document.readyState) > -1) {
    while(window.readyHandlers.length > 0) {
      (window.readyHandlers.shift())();
    }
  }
};

document.onreadystatechange = window.handleState;

Utilisation:

ready(function () {
  // your code here
});

c'est écrit pour gérer le chargement asynchrone de JS mais vous pourriez vouloir synchroniser ce script d'abord sauf si vous êtes en train de minifier. J'ai trouvé utile dans le développement.

navigateurs modernes prennent également en charge async chargement de scripts qui améliore encore l'expérience. La prise en charge de async signifie que plusieurs scripts peuvent être téléchargés simultanément tout en rendant la page. Il suffit de faire attention en fonction des autres scripts chargés de manière asynchrone ou d'utiliser une minifieuse ou quelque chose comme browserify pour gérer les dépendances.

73
répondu PhilT 2016-12-03 07:46:51

les gens de bien à HubSpot ont une ressource où vous pouvez trouver des méthodologies Javascript pures pour atteindre beaucoup de bonté jQuery - y compris ready

http://youmightnotneedjquery.com/#ready

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

exemple d'utilisation en ligne:

ready(function() { alert('hello'); });
17
répondu Lorcan O'Neill 2016-10-28 17:39:15

Votre méthode (l'insertion de script avant la balise de fermeture body)

<script>
   myFunction()
</script>
</body>
</html>

est un moyen fiable de prendre en charge les navigateurs anciens et nouveaux.

7
répondu Kernel James 2016-10-28 16:38:38

Prêt

function ready(fn){var d=document;(d.readyState=='loading')?d.addEventListener('DOMContentLoaded',fn):fn();}

utiliser comme

ready(function(){
    //some code
});

Pour l'auto invoquant le code

(function(fn){var d=document;(d.readyState=='loading')?d.addEventListener('DOMContentLoaded',fn):fn();})(function(){

    //Some Code here
    //DOM is avaliable
    //var h1s = document.querySelector("h1");

});

Support: IE9+

4
répondu Vitim.us 2015-11-24 05:15:53

Je ne suis pas tout à fait sûr de ce que vous demandez, mais peut-être que cela peut aider:

window.onload = function(){
    // Code. . .

}

ou:

window.onload = main;

function main(){
    // Code. . .

}
3
répondu Zak The Hat 2017-10-13 14:01:36

Voici une version nettoyée, Non-eval-using De Ram-swaroop "fonctionne dans tous les navigateurs" variété -- fonctionne dans tous les navigateurs!

function onReady(yourMethod) {
  var readyStateCheckInterval = setInterval(function() {
    if (document && document.readyState === 'complete') { // Or 'interactive'
      clearInterval(readyStateCheckInterval);
      yourMethod();
    }
  }, 10);
}
// use like
onReady(function() { alert('hello'); } );

il ne faut pas attendre 10 ms de plus pour courir, donc voici une façon plus compliquée qui ne devrait pas:

function onReady(yourMethod) {
  if (document.readyState === 'complete') { // Or also compare to 'interactive'
    setTimeout(yourMethod, 1); // Schedule to run immediately
  }
  else {
    readyStateCheckInterval = setInterval(function() {
      if (document.readyState === 'complete') { // Or also compare to 'interactive'
        clearInterval(readyStateCheckInterval);
        yourMethod();
      }
    }, 10);
  }
}

// Use like
onReady(function() { alert('hello'); } );

// Or
onReady(functionName);

Voir aussi Comment vérifier si DOM est prêt sans cadre? .

3
répondu rogerdpack 2018-04-13 16:00:19

document.ondomcontentready=function(){} devrait faire l'affaire, mais il n'a pas la compatibilité complète du navigateur.

semble que vous devriez juste utiliser jQuery min

2
répondu maxhud 2013-05-16 22:47:57