D'accord, c'est peut-être une question idiote, même si je suis sûr qu'il y a beaucoup d'autres personnes qui posent la même question de temps en temps. Moi, je veux juste en être sûr à 100%. Avec jQuery, nous connaissons tous le merveilleux
$('document').ready(function(){});
Cependant, supposons que je souhaite exécuter une fonction écrite en JavaScript standard sans aucune bibliothèque le sauvegardant, et que je souhaite lancer une fonction dès que la page est prête à la gérer. Quelle est la bonne façon d'aborder cela?
Je sais que je peux faire:
window.onload="myFunction()";
... ou je peux utiliser la balise body
:
<body onload="myFunction()">
... ou je peux même essayer au bas de la page après tout, mais la balise end body
ou html
ressemble à ceci:
<script type="text/javascript">
myFunction();
</script>
Qu'est-ce qu'une méthode compatible avec plusieurs navigateurs (ancien/nouveau) permettant d'émettre une ou plusieurs fonctions à la manière de jQuery $.ready()
?
La chose la plus simple à faire en l’absence d’un cadre prenant en charge toute la compatibilité entre navigateurs consiste simplement à appeler votre code à la fin du corps. Cela est plus rapide à exécuter qu'un gestionnaire onload
car il attend seulement que le DOM soit prêt, pas pour 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 d'une compatibilité entre navigateurs et que vous ne voulez pas attendre window.onload
, alors vous devriez probablement aller voir comment un framework comme jQuery implémente sa $(document).ready()
méthode. C'est assez impliqué en fonction des capacités du navigateur.
Pour vous donner une petite idée de ce que fait jQuery (ce qui fonctionnera partout où la balise script est placée).
Si supporté, il essaye le standard:
document.addEventListener('DOMContentLoaded', fn, false);
avec un repli sur:
window.addEventListener('load', fn, false )
ou pour les anciennes versions d'IE, il utilise:
document.attachEvent("onreadystatechange", fn);
avec un repli sur:
window.attachEvent("onload", fn);
Et, il y a quelques solutions de contournement dans le chemin de code IE que je ne suis pas très bien, mais il semble que cela ait quelque chose à voir avec les cadres.
Voici un substitut complet pour .ready()
de jQuery écrit en javascript:
(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ée publiquement sur GitHub à l’adresse https://github.com/jfriend00/docReady
Usage:
// 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);
Cela 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
Mise en oeuvre et banc d’essai: http://jsfiddle.net/jfriend00/YfD3C/
Voici un résumé de la façon dont cela fonctionne:
docReady(fn, context)
docReady(fn, context)
est appelé, vérifiez si le gestionnaire Prêt est déjà activé. Si c'est le cas, programmez simplement le rappel nouvellement ajouté pour qu'il soit déclenché juste après que ce thread de JS se termine avec setTimeout(fn, 1)
.document.addEventListener
existe, installez des gestionnaires d'événements en utilisant .addEventListener()
pour les deux événements "DOMContentLoaded"
et "load"
. Le "chargement" est un événement de sauvegarde pour la sécurité et ne devrait pas être nécessaire.document.addEventListener
n'existe pas, installez des gestionnaires d'événements en utilisant .attachEvent()
pour "onreadystatechange"
et "onload"
.onreadystatechange
, vérifiez si le document.readyState === "complete"
et, le cas échéant, appelez une fonction pour déclencher tous les gestionnaires prêts.Les gestionnaires enregistrés avec docReady()
ont la garantie d'être licenciés dans l'ordre dans lequel ils ont été enregistrés.
Si vous appelez docReady(fn)
après que le document est déjà prêt, l'exécution du rappel est planifiée dès que le thread d'exécution en cours est terminé avec setTimeout(fn, 1)
. Cela permet au code d'appel de toujours supposer qu'il s'agit de rappels asynchrones qui seront appelés ultérieurement, même si plus tard le sera dès que le thread actuel de JS se terminera et qu'il préservera l'ordre d'appel.
Je voudrais mentionner certaines des manières possibles ici avec une astuce pure en javascript qui fonctionne sur 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!');
});
L'astuce ici, comme l'explique le auteur d'origine , est que nous vérifions la propriété document.readyState . S'il contient la chaîne in
(comme dans uninitialized
et loading
, les deux premiers états de disponibilité DOM sur 5), nous fixons un délai d'expiration et vérifions à nouveau. Sinon, nous exécutons la fonction passée.
Et voici le jsFiddle pour l'astuce qui fonctionne sur tous les navigateurs.
Merci à Tutorialzine d’avoir inclus cela dans leur livre.
Si vous faites Vanilla simple JavaScript sans jQuery, 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!");
});
Ce qui pourrait aussi être écrit SHORTHAND comme ceci, qui jQuery sera exécuté après le prêt même se produit .
$(function() {
console.log("ready!");
});
Ne pas confondre avec BELOW (qui n'est pas censé être prêt pour le DOM):
NE PAS utiliser un IIFE comme ceci qui s'exécute automatiquement:
Example:
(function() {
// Your page initialization code here - WRONG
// The DOM will be available here - WRONG
})();
Cet IIFE n'attendra PAS le chargement de votre DOM. (Je parle même de la dernière version du navigateur Chrome!)
Testé dans IE9 et les derniers 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/
UPDATE - version réutilisable
Je viens de développer ce qui suit. C'est un équivalent assez simpliste de jQuery ou Dom ready sans compatibilité avec les versions antérieures. Cela a probablement besoin d'être peaufiné. Testé dans les dernières versions de Chrome, Firefox et IE (10/11) et devrait fonctionner dans les navigateurs plus anciens comme indiqué. Je mettrai à jour si je trouve des 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;
Usage:
ready(function () {
// your code here
});
Il est écrit pour gérer le chargement asynchrone de JS, mais vous voudrez peut-être tout d'abord synchroniser ce script, sauf si vous réduisez la taille. Je l'ai trouvé utile en développement.
Les navigateurs modernes prennent également en charge le chargement asynchrone des scripts, ce qui améliore encore l'expérience. La prise en charge async signifie que plusieurs scripts peuvent être téléchargés simultanément tout en restituant la page. Faites simplement attention lorsque vous dépendez d'autres scripts chargés de manière asynchrone ou utilisez un minifier ou quelque chose comme browserify pour gérer les dépendances.
Les bons employés de HubSpot ont une ressource où vous pouvez trouver des méthodologies Javascript pures pour obtenir beaucoup de qualité 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'); });
Votre méthode (placer le script avant la balise body de fermeture)
<script>
myFunction()
</script>
</body>
</html>
est un moyen fiable de prendre en charge les anciens et les nouveaux navigateurs.
Je ne sais pas trop ce que vous demandez, mais peut-être que cela peut aider:
window.onload = function(){
// Code. . .
}
Ou:
window.onload = main;
function main(){
// Code. . .
}
function ready(fn){var d=document;(d.readyState=='loading')?d.addEventListener('DOMContentLoaded',fn):fn();}
Utiliser comme
ready(function(){
//some 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");
});
Soutien: IE9 +
Voici une version nettoyée et non utilisable par eval de la variété Ram-swaroop's "fonctionne dans tous les navigateurs" - 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'); } );
Cependant, il attend 10 ms supplémentaires pour fonctionner. Voici donc un moyen plus compliqué 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 framework?.
document.ondomcontentready=function(){}
devrait faire l'affaire, mais il n'est pas complètement compatible avec le navigateur.
On dirait que vous devriez juste utiliser jQuery min