Si je veux qu'une fonction soit exécutée, je préfère faire js en ligne:
<p id="element" onclick="doSomething();">Click me</p>
car il est plus facile de déboguer.
Cependant, j'entends des gens dire de ne pas utiliser inline js, et fais:
document.getElementById('element').onclick = doSomething;
Pourquoi le js event listener est-il recommandé?
Fondamentalement, cela a à voir avec tout garder tout séparé, je crois. Donc, gardez HTML/CSS/JS tous séparés. Cela rend votre HTML plus ordonné et, je pense, plus facile à naviguer sans.
Ensuite, lorsque/si vous devez effectuer des modifications importantes, vous disposez de suffisamment d'espace pour déplacer le JS intégré dans un fichier externe de toute façon OR si vous souhaitez appliquer la même fonction à plusieurs boutons, moins de code. Et moins de code est un endroit plus heureux
Si vos fichiers JS sont correctement et minutieusement documentés, leur navigation par une personne extérieure est facilitée.
Un gros argument contre les gestionnaires d’événements en ligne, et l’argument qui est traité par les autres réponses ici est la séparation de la présentation et de la logique .
Cependant, il existe en réalité un problème plus important. IMO: La manière en quelque sorte insaisissable d'évaluer les gestionnaires d'événements en ligne.
Comme vous le savez peut-être, le contenu des attributs on*
sera utilisé comme corps de la fonction de gestionnaire d'événements. Mais quelles sont les caractéristiques de cette fonction?
Une des plus surprenantes est que les propriétés de certains éléments ancêtres et de l’élément lui-même se trouvent dans le scope du gestionnaire d’événements en ligne.
<form>
<input name="foo" />
<button type="button" onclick="console.log(foo); console.log(window.foo);">
Click me
</button>
<div onclick="console.log(foo);">Click me as well!</div>
</form>
En cliquant sur les journaux button
<input name="foo"></input>
undefined
dans la console. Le fait que window.foo
soit undefined
vous indique qu'il n'y a pas de variable globale foo
. Alors d'où vient la variable foo
? Pourquoi console.log(foo)
enregistre-t-il l'élément d'entrée et ne génère pas d'erreur de référence?
Parce que les propriétés de l'élément form
se trouvent dans la portée du gestionnaire d'événements et que l'élément form
a une propriété pour chaque élément de contrôle de formulaire nommé qu'il contient. Vous pouvez facilement tester ceci avec console.log(document.querySelector('form').foo)
.
Maintenant, en cliquant sur l'élément div
, une erreur de référence est générée:
ReferenceError: foo is not defined
Donc, apparemment, l'élément form
n'entre que dans la portée des éléments de contrôle de formulaire, pas avec un descendant. Comment est-ce déroutant?
De même, les propriétés de l'objet document
font également partie des gestionnaires d'événements inline, ce qui peut conduire à des bogues surprenants (saviez-vous que document
a une propriété plugins
?).
Le mode d’évaluation exact des gestionnaires d’événements inline est formalisé dans la spécification HTML5 . Ayez une boucle à l’étape 10, en particulier lorsque la création de la chaîne d’étendue est décrite.
Conclusion :
En raison de cette implicite connexion entre les éléments et les gestionnaires d'événements en ligne, il peut être très difficile de suivre un bogue. Il va de soi que vous pouvez utiliser des gestionnaires d'événements en ligne si vous souhaitez simplement tester quelque chose. Mais leur utilisation dans le code de production entraîne un coût de maintenance plus élevé.
Les articles de quirksmode.org expliquent très bien les différentes manières de lier les gestionnaires d’événements et leurs (dés) avantages.
Il existe de nombreuses raisons d'éviter JavaScript en ligne et l'une des plus importantes est peut-être la maintenabilité du code.
Un exemple rapide (j'utilise jQuery simplement à des fins de démonstration).
<p class="element" onclick="doSomething();">Click me</p>
<p class="element" onclick="doSomething();">Click me</p>
<p class="element" onclick="doSomething();">Click me</p>
<p class="element" onclick="doSomething();">Click me</p>
<p class="element" onclick="doSomething();">Click me</p>
<p class="element" onclick="doSomething();">Click me</p>
Et si soudainement vous recevez une demande pour changer tous vos paragraphes pour exécuter une autre fonction? Dans votre exemple, vous devez tout changer manuellement dans votre code HTML. Cependant, si vous choisissez de séparer le HTML du JavaScript, vous pouvez simplement le faire comme ceci.
<p class="element">Click me</p>
<p class="element">Click me</p>
<p class="element">Click me</p>
<p class="element">Click me</p>
<p class="element">Click me</p>
<p class="element">Click me</p>
$('.element').bind('click', doSomethingElse);
Le code HTML est également plus propre, ce qui permet aux concepteurs de se concentrer exclusivement sur le design sans craindre de perdre quelque chose en travaillant sur un projet qui implique également d'autres personnes.
EDIT: Donner un exemple pour mon commentaire ci-dessous.
Project = {
// All the variables/constants/objects that need to be globally accessible inside the Project object.
init : function(){
// Main entry point...
this.MainMenu.init();
// Rest of the code which should execute the moment Project is initiated.
}
}
Project.MainMenu = {
// All the variables/constants/objects that need to be accessible only to MainMenu.
init : function(){ // Is run immediatelly by Project.init()
// Event handlers relevant to the main menu are bound here
// Rest of the initialization code
}
}
Project.SlideShow = {
// All the variables/constants/objects that need to be accessible only to SlideShow.
init : function(){ // Is run only on pages that really require it.
// Event handlers for the slideshow.
}
}
En dépit de ce que d’autres peuvent penser, je pense que l’ajout d’auditeurs dans le balisage présente une valeur réductrice. Plus précisément, cela vous donne beaucoup plus de liberté pour modifier les nœuds DOM. Si vous ajoutez des auditeurs via JavaScript, ceux-ci sont perdus lorsque vous remplacez le innerHTML de tout nœud parent. Si vous alignez les écouteurs dans le balisage, vous pouvez cloner le nœud, y apporter des modifications, puis remplacer le nœud d'origine par le nœud que vous venez de cloner et de modifier.
Peut-être est-il préférable de le décrire dans un cas d'utilisation spécifique. Je souhaite apporter des modifications à plusieurs parties du document sans provoquer de redistribution à plusieurs reprises. Donc, dans ce cas, je peux cloner le nœud, y apporter des modifications (pas de refusion depuis son détachement), puis remplacer le nœud précédent par le nœud modifié (déclencher un refoulement). Avec les écouteurs en ligne, cela évite que des écouteurs ne se perdent pendant le remplacement.
Je vois des gens dire qu'il faut séparer les préoccupations concernant la présentation et la logique d'entreprise.
OP dans son exemple montre bien cette séparation! Il n'y a pas de logique dans le gestionnaire d'événements en ligne, mais simplement une référence/appel à une fonction qui sera exécuté sur l'événement "clic" ... la logique elle-même peut être gérée séparément ailleurs.
Personnellement, je préfère cette approche en raison de la découvrabilité des flux logiques. Si je n'ai jamais vu d'application auparavant ... le premier endroit où je commencerai mon parcours de code se trouve dans le DOM manutentionnaires. En utilisant, disons, une approche d'événement "JQuery.On", il vous suffirait de parcourir le code HTML pour savoir quels gestionnaires sont réellement connectés et fournissent des fonctionnalités.
Les gestionnaires d’événements en ligne qui fournissent simplement des pointeurs aux fonctions ne font que brancher les événements et ne fuient pas la logique dans la présentation.
En dehors de la perspective des normes de codage
Utilisation d'attributs:
<p id="element" onclick="doSomething();">Click me</p>
si vous ajoutez à nouveau le même attribut (voir ci-dessous), le dernier est considéré.
<p id="element" onclick="doSomethingMore();">Click me</p>
Utilisation du gestionnaire d'événements:
document.getElementById('element').onclick = doSomething;
et disons que vous avez ajouté la ligne ci-dessous
document.getElementById('element').onclick = doSomethingMore;
Les deux gestionnaires sont appelés.
Vous pouvez en dire autant de CSS et des styles inline. Il serait facile de ne pas avoir à parcourir un fichier CSS pour trouver la classe/id en cours, ou les éléments parent/enfant avec lesquels vous travaillez.
Est-il vraiment préférable de lier un clic pour dire 10 éléments différents en ligne? Ou juste un gestionnaire d'événements ciblant une classe? Même si vous n'avez pas besoin de gestionnaires de clic 10, il est toujours préférable de configurer votre code pour qu'il soit maintenable et pour qu'il soit mis à niveau ultérieurement.
Je ne suis pas au courant de l'avantage d'utiliser un gestionnaire en ligne par rapport à l'attachement du gestionnaire plus tard. Dans mon expérience, je préfère utiliser la méthode inline lorsque je dois traiter des éléments dynamiques, par exemple si je veux ajouter un gestionnaire à chaque image et que le nombre d'images change en fonction d'autres données (ex images dans db). Dans ce cas, utiliser inline me permet d’ajouter un gestionnaire à chaque image, sinon je dois recalculer le nombre d’images dans le fichier javascript afin d’attacher et de gérer chaque image.
Bien sûr, quand vous pouvez utiliser des bibliothèques comme jQuery où vous pouvez facilement obtenir la liste des éléments en ligne ne sont pas utiles