2010-01-23 5 views
3

oK, donc j'en ai quelques-uns, ce qui peut finir par être pour ce forum des questions trop novices concernant la gestion d'événements discrète.Problèmes de gestion des événements (Javascript)

Si je comprends bien, un document mis en place correctement ressemblerait à quelque chose comme ceci:

<html> 
<head> 
<title>Title</title> 
<script src="jsfile.js" type="text/javascript></script> 
</head> 
<body> 

//Body content, like some form elements in my case 

</body> 
</html> 

Jsfile.js ressemblerait à quelque chose comme ceci:

function a() { 
//code; 
} 
function b()... 

window.addEventListener('load', a, false); 
document.getElementById("id").addEventListener('click', b, false); 
document.myForm.typeSel.addEventListener('change', c, false); 

//or to use better browser-compatible code... 

function addEvent(obj,evt,fn) { 
if (obj.addEventListener) 
    obj.addEventListener(evt,fn,false); 
else if (obj.attachEvent) 
    obj.attachEvent('on'+evt,fn); 
} 
addEvent(window, 'load', a); 
addEvent(document.getElementById('id'), 'click', b); 
addEvent(document.myForm.typeSel, 'change', c); 

Si je comprends bien, tout en Dans la tête, le navigateur va charger ce code javascript, en ajoutant chacun de ces gestionnaires d'événements à leurs éléments respectifs. TOUTEFOIS ... Tandis que le gestionnaire de fenêtre est ajouté correctement, aucun des autres ne l'est. Mais s'il est placé dans une fonction, la méthode (par exemple) getElementById d'accès à un élément fonctionne correctement, et le gestionnaire d'événements est ajouté. Donc, je pourrais concevoir une fonction loadEvents() qui est appelée via window onload, qui contient toutes les fonctions addEvent() pour les autres éléments de document pour lesquels j'ai besoin de gestionnaires d'événements. Mais si je comprends bien le tout, je ne devrais pas avoir à faire cela.

En outre, si je devais coller le code addEvent dans le corps ainsi que l'élément auquel il répond, comme ...

<input type="checkbox" id="test" /> 
<script type="text/javascript> 
document.getElementById("test").onclick = func; 
</script> 

... il fonctionne très bien. Mais bien sûr, cela viole également toute la raison de la suppression des gestionnaires d'événements en ligne!

Alors question étant: Pour utiliser "élément .addEventListener (clic, func, false)", "addEvent (élément 'cliquez sur', func)", ou même "élément .onclick = func "- comment puis-je référencer avec succès un élément à la fin d'un fichier script dans la tête, sans avoir à le coller dans une autre fonction? Pourquoi getElementById et d'autres méthodes ne fonctionnent pas en dehors d'une fonction dans la tête?

Ou, y a-t-il une faille dans ma compréhension sous-jacente?

Répondre

2

Mettre <script> dans le <head> utilisé pour être la sagesse. Mais de nos jours, avec de lourdes pages ajax, <script> est de plus en plus souvent mais dans le corps, aussi loin en bas que possible. L'idée est que le chargement et l'analyse du <script> empêchent le chargement de la page, de sorte que l'utilisateur regarde une page vierge. En s'assurant que le corps est chargé aussi vite que possible, vous donnez à l'utilisateur quelque chose à regarder. Voir les meilleures pratiques de YAHOO pour une excellente explication sur cette question: http://developer.yahoo.com/performance/rules.html

Maintenant, indépendamment de ce problème, le code tel que vous l'avez configuré maintenant, ne peut pas fonctionner - au moins, pas lorsque les éléments que vous essayez de joindre le les gestionnaires ne sont pas encore créés. Par exemple, dans cette ligne:

document.getElementById("id").addEventListener('click', b, false); 

vous obtiendrez une erreur d'exécution si l'élément avec id="id" est à l'intérieur du corps. Maintenant, si vous mettez le <script> dans le corps, bien au-dessous, après le contenu (y compris le lement avec id="id", cela fonctionnera simplement, puisque le script est exécuté après que le code html pour ces éléments soit analysé et ajouté au DOM.

Si vous voulez avoir le script dans la tête, alors vous pouvez le faire, mais vous devrez synchroniser l'ajout des gestionnaires d'événements avec le rendu du contenu de la page. Vous pouvez le faire en les ajoutant tous dans le gestionnaire de chargement de document ou de fenêtre. Donc, si vous écrivez:

//cross browser add event handler 
function addEventHandler(obj,evt,fn) { 
    if (obj.addEventListener) { 
     obj.addEventListener(evt,fn,false); 
    } else if (obj.attachEvent) { 
     obj.attachEvent('on'+evt,fn); 
    } 
} 
addEventHandler(document, 'load', function(){ 
    //set up all handlers after loading the document 
    addEventHandler(document.getElementById('id'), 'click', b); 
    addEventHandler(document.myForm.typeSel, 'change', c); 
}); 

cela fonctionne.

+0

Merci beaucoup. Je me bousculais pour ne pas y penser. J'étais même allé jusqu'à mettre une alerte dans ma fonction addEvent(), pour découvrir quel objet avait été envoyé via l'argument, et découvert qu'il était "indéfini". J'aurais dû le comprendre logiquement. Tant pis. En outre, merci pour le lien vers la page Yahoo - Je suis toujours à la recherche de moyens pour m'assurer que je suis en train de coder selon les normes les plus élevées, comme la mise à jour discrète javascript ... la première place! – David

+0

Pas besoin de vous lancer :) Pour moi, la programmation est toujours un mélange de logique et d'essais et d'erreurs. Je pense que c'est comme ça pour la plupart des gens, sinon nous n'aurions pas autant de frameworks de tests de logiciels. En ce qui concerne le codage selon les normes les plus élevées ... Je ne sais pas, il est certainement bon d'être conscient de ce que vous faites, et pourquoi vous le faites. Mais ce qui est considéré comme un standard élevé d'un POV peut être désapprouvé par un autre. –

0

connaissez-vous jQuery?
est une bibliothèque javascript avec des outils vraiment géniaux. Par exemple, si vous souhaitez que certaines actions js soient effectuées juste après votre page si elles sont entièrement chargées et que tous les éléments DOM sont créés (pour éviter ces exceptions ennuyantes), vous pouvez simplement utiliser la méthode ready().
aussi je vois que vous voulez attacher click \ change événements jQuery prend également soin de ceci :) et vous n'avez pas à vous soucier de tous ces problèmes entre les navigateurs.
jetez un oeil à jQuery selectors pour vous rendre la vie plus facile lorsque vous tentez d'aller chercher un élément.

Eh bien c'est tout, il suffit de donner un coup de feu, il a une API très intuitive et une bonne documentation.

+0

Merci pour le conseil, je vais être sûr de vérifier. – David

1

La raison pour laquelle window.addEventListener œuvres tout en document.getEle...().addEventListener qui ne fonctionne pas est simple: objet window existe lorsque vous exécuter ce code alors que l'élément avec id="abc" est pas encore chargé. Lorsque votre navigateur télécharge les sources de la page, le code source est analysé et exécuté dès que possible. Donc, si vous placez script dans l'élément head - au tout début de la source - il est exécuté avant que certains <div id="abc">...</div> soient téléchargés. Je pense que maintenant vous savez pourquoi

<div id="test">Blah</div> 
<script type="text/javascript">document.getElementById("test").style.color = "red";</script> 

œuvres, alors que ce:

<script type="text/javascript">document.getElementById("test").style.color = "red";</script> 
<div id="test">Blah</div> 

ne fonctionne pas.

Vous pouvez gérer ce problème de plusieurs façons. Les plus populaires sont:

  • mettre les scripts à la fin du document (juste avant </body>)
  • en utilisant des événements pour retarder l'exécution des scripts

La première devrait être clair en ce moment, mais personnellement Je préfère le dernier (même si c'est un peu pire).

Alors, comment gérer les événements? Lorsque le navigateur télécharge enfin et analyse la source entière, l'événement DOMContentLoaded est exécuté. Cet événement signifie que la source est prête et que vous pouvez manipuler DOM en utilisant JavaScript.

window.addEventListener("DOMContentLoaded", function() { 
    //here you can safely use document.getElementById("...") etc. 
}, false); 

Malheureusement pas tous visionneur événement DOMContentLoaded, mais comme toujours ... Google is the anwser. Mais ce n'est pas la fin des mauvaises nouvelles. Comme vous avez remarqué addEventListener n'est pas bien pris en charge par IE. Eh bien ... ce navigateur rend vraiment la vie difficile et vous devrez pirater une chose de plus ... Yes... once again - Google. Mais c'est IE donc ce n'est pas tout.Navigateurs normaux (comme Opera ou Firefox) prend en charge W3C Event Model tandis que IE prend en charge its own - encore une fois - Google pour la solution de navigateur croisé.

addEventListener peut sembler maintenant le pire moyen d'attacher des événements, mais en fait c'est le meilleur. Il vous permet d'ajouter ou de supprimer facilement de nombreux écouteurs pour un seul événement sur un seul élément.

PS. J'ai remarqué que vous envisagez d'utiliser l'événement Load pour exécuter vos scripts. Ne fais pas ça. L'événement Load est exécuté trop tard. Vous devez attendre que chaque image ou fichier soit chargé. Vous devriez utiliser l'événement DOMContentLoaded. J'ai oublié ... traitant avec le modèle d'événement cross-navigateur est beaucoup plus facile lorsque vous utilisez un cadre comme très populaire jQuery. Mais c'est bon de savoir comment fonctionnent les navigateurs.