En l'absence d'un framework qui assure la compatibilité entre navigateurs, le plus simple est de placer un appel à votre code à la fin du corps du texte. Cette méthode est plus rapide à exécuter qu'un onload
car il attend seulement que le DOM soit prêt, et non que toutes les images soient chargées. Et cela fonctionne dans tous les navigateurs.
<!doctype html>
<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>
Pour les navigateurs modernes (à partir d'IE9 et plus récents et toute version de Chrome, Firefox ou Safari), si vous voulez être en mesure de mettre en œuvre une fonction jQuery comme $(document).ready()
que vous pouvez appeler de n'importe où (sans vous soucier de l'emplacement du script appelant), vous pouvez simplement utiliser quelque chose comme ceci :
function docReady(fn) {
// see if DOM is already available
if (document.readyState === "complete" || document.readyState === "interactive") {
// call on next available tick
setTimeout(fn, 1);
} else {
document.addEventListener("DOMContentLoaded", fn);
}
}
Utilisation :
docReady(function() {
// DOM is loaded and ready for manipulation here
});
Si vous avez besoin d'une compatibilité totale entre les différents navigateurs (y compris les anciennes versions d'IE) et que vous ne voulez pas attendre la mise en place de l window.onload
alors vous devriez probablement aller voir comment un framework comme jQuery implémente son $(document).ready()
méthode. Elle est assez complexe et dépend des 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).
S'il est supporté, il essaie la norme :
document.addEventListener('DOMContentLoaded', fn, false);
avec une solution de repli :
window.addEventListener('load', fn, false )
ou pour les anciennes versions d'IE, il utilise :
document.attachEvent("onreadystatechange", fn);
avec une solution de repli :
window.attachEvent("onload", fn);
Et il existe des solutions de contournement dans le chemin de code d'IE que je ne suis pas tout à fait, mais il semble que cela ait quelque chose à voir avec les cadres.
Voici un substitut complet de la méthode jQuery .ready()
é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 suivante 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
Mise en œuvre et banc d'essai : http://jsfiddle.net/jfriend00/YfD3C/
Voici un résumé de son fonctionnement :
- Créer un IIFE (expression de fonction immédiatement invoquée) afin que nous puissions avoir des variables d'état non publiques.
- Déclarer une fonction publique
docReady(fn, context)
- Cuando
docReady(fn, context)
est appelé, vérifiez si le gestionnaire ready a déjà été activé. Si c'est le cas, il suffit de programmer le nouveau callback pour qu'il se déclenche juste après que ce fil de JS se termine avec setTimeout(fn, 1)
.
- Si le gestionnaire ready n'a pas encore été activé, ajoutez ce nouveau rappel à la liste des rappels à appeler ultérieurement.
- Vérifiez si le document est déjà prêt. Si oui, exécutez tous les gestionnaires de documents prêts.
- Si nous n'avons pas encore installé de récepteurs d'événements pour savoir quand le document est prêt, installez-les maintenant.
- Si
document.addEventListener
existe, puis installez les gestionnaires d'événements en utilisant .addEventListener()
pour les deux "DOMContentLoaded"
y "load"
événements. La "charge" est un événement de secours pour la sécurité et ne devrait pas être nécessaire.
- Si
document.addEventListener
n'existe pas, alors installez des gestionnaires d'événements en utilisant .attachEvent()
pour "onreadystatechange"
y "onload"
événements.
- Dans le
onreadystatechange
vérifiez si l'événement document.readyState === "complete"
et si c'est le cas, appeler une fonction pour déclencher tous les gestionnaires prêts.
- Dans tous les autres gestionnaires d'événements, appelez une fonction pour déclencher tous les gestionnaires prêts.
- Dans la fonction qui appelle tous les gestionnaires prêts, vérifiez une variable d'état pour voir si nous avons déjà tiré. Si c'est le cas, ne faites rien. Si nous n'avons pas encore été appelés, alors bouclez à travers le tableau des fonctions prêtes et appelez chacune d'entre elles dans l'ordre où elles ont été ajoutées. Définissez un drapeau pour indiquer qu'elles ont toutes été appelées afin qu'elles ne soient jamais exécutées plus d'une fois.
- Effacer le tableau des fonctions pour que toutes les fermetures qu'elles utilisent puissent être libérées.
Manipulateurs enregistrés auprès de docReady()
sont garantis d'être tirés dans l'ordre où ils ont été enregistrés.
Si vous appelez docReady(fn)
alors que le document est déjà prêt, la fonction de rappel sera programmée pour être exécutée dès que le fil d'exécution actuel sera terminé en utilisant la fonction setTimeout(fn, 1)
. Cela permet au code appelant de toujours supposer qu'il s'agit de callbacks asynchrones qui seront appelés plus tard, même si plus tard est dès que le thread actuel de JS se termine et cela préserve l'ordre d'appel.
1 votes
La prise en charge des anciens navigateurs est une bonne chose, mais étant donné la vitesse à laquelle la technologie progresse et le fait que les gens semblent rattraper leur retard plus rapidement de nos jours, elle n'est pas nécessaire à 100 %, mais c'est un bon bonus si possible. Dans l'ensemble, j'essaie de comprendre si l'un de ces éléments est la norme dans les navigateurs. Est-ce qu'ils fonctionnent tous ? Le choix du navigateur est-il important ? S'ils fonctionnent tous, quel serait le meilleur choix par rapport aux autres ?
11 votes
Voir ça : stackoverflow.com/questions/799981/
0 votes
@clexmond mettre script en bas vs en haut est quelque chose que j'ai toujours compris pour diverses raisons. J'ai tendance à le placer en bas, dans des fichiers externes ou sur la page elle-même. Mais ces deux dernières années, j'ai été gâté par jQuery et d'autres libraires. Cependant, je suis maintenant dans une sorte de croisade pour essayer de mieux comprendre le javascript par lui-même, sans libraire. Donc, malgré ce que je sais de javascript, cette simple petite chose me déstabilise un peu car je veux m'assurer que tout script que je fais suit une méthodologie compatible avec tous les navigateurs.
4 votes
Vous pouvez consulter les sources de jQuery pour voir comment ils implémentent la fonction "document ready" et travailler à partir de là.
0 votes
@DanA. Bien. Je pense que cela résume un peu la réponse à cette question. Donc JavaScript seul, il n'y a pas de moyen absolu de trouver facilement un état prêt, une sorte de moyen doit être créé pour le supporter à travers les différents navigateurs. Merci d'avoir trouvé cela et de l'avoir clarifié pour moi.
0 votes
@chris, c'est vrai. Je ne connais pas la fonction document.ondoncontentready mentionnée par maxhud, mais si elle devient standardisée, je suppose que c'est l'équivalent de ce que jQuery a maintenant.
0 votes
@DanA. : Je ne vois pas comment ce message répond à la question de la compatibilité entre navigateurs de l'interface utilisateur.
onload
événement debody
ou de placer le script en bas de la page. Je ne suis pas au courant d'un quelconque problème de croisement de navigateurs. Et vous ?0 votes
@amnotiam Non, je pense que onload est assez standard, si vous avez seulement besoin de charger la structure DOM. Ce serait le moyen le plus simple de le faire.
0 votes
@DanA. cela répond à la question de savoir ce que je cherchais plus ou moins en voyant comment jQuery le gère tout autour me dit que malgré le fait que onload soit une méthode semi directe/standard en quelque sorte, cela ne signifie pas qu'elle fonctionnera dans toutes les situations avec tous les navigateurs, en fonction des besoins de la fonction que je veux construire et appeler. Dans l'ensemble, je cherche juste à savoir quand le DOM est entièrement chargé, ce que onload semble couvrir, mais, en même temps, je voulais voir laquelle des méthodes ci-dessus était une façon plus conforme d'aborder la question.