970 votes

AddEventListener vs onclick

Quelle est la différence entre addEventListener et onclick?

var h = document.getElementById("a");
h.onclick = dothing1;
h.addEventListener("click", dothing2);

Le code ci-dessus réside ensemble dans un fichier .js séparé, et ils fonctionnent tous les deux parfaitement.

1223voto

Chris Points 20836

Les deux sont correctes, mais aucune n'est "meilleure" en soi, et il peut y avoir une raison pour laquelle le développeur a choisi d'utiliser les deux approches.

Écouteurs d'événements (addEventListener et attachEvent d'IE)

Les versions antérieures d'Internet Explorer mettent en œuvre le javascript différemment de presque tous les autres navigateurs. Avec les versions inférieures à 9, vous utilisez la fonction attachEvent [ doc comme ceci :

element.attachEvent('onclick', function() { /* do stuff here*/ });

Dans la plupart des autres navigateurs (y compris IE 9 et supérieur), vous utilisez addEventListener [ doc ], comme ceci :

element.addEventListener('click', function() { /* do stuff here*/ }, false);

En utilisant cette approche ( Événements du niveau 2 de DOM ), vous pouvez attacher un nombre théoriquement illimité d'événements à un seul élément. La seule limite pratique est la mémoire côté client et d'autres problèmes de performance, qui sont différents pour chaque navigateur.

Les exemples ci-dessus représentent l'utilisation d'une fonction anonyme[ doc ]. Vous pouvez également ajouter un écouteur d'événements en utilisant une référence de fonction [ doc ] ou une fermeture[ doc ] :

var myFunctionReference = function() { /* do stuff here*/ }

element.attachEvent('onclick', myFunctionReference);
element.addEventListener('click', myFunctionReference , false);

Une autre caractéristique importante de addEventListener est le dernier paramètre, qui contrôle la façon dont l'écouteur réagit aux événements de bulles[ doc ]. J'ai passé false dans les exemples, ce qui est standard pour probablement 95% des cas d'utilisation. Il n'y a pas d'argument équivalent pour attachEvent ou lors de l'utilisation d'événements en ligne.

Événements en ligne (propriété HTML onclick="" et element.onclick)

Dans tous les navigateurs qui supportent le javascript, vous pouvez placer un écouteur d'événements en ligne, c'est-à-dire directement dans le code HTML. Vous avez probablement vu ceci :

<a id="testing" href="#" onclick="alert('did stuff inline');">Click me</a>

La plupart des développeurs expérimentés fuient cette méthode, mais elle permet de faire le travail ; elle est simple et directe. Vous ne pouvez pas utiliser de fermetures ou de fonctions anonymes ici (bien que le gestionnaire lui-même soit une fonction anonyme en quelque sorte), et votre contrôle de la portée est limité.

L'autre méthode que vous mentionnez :

element.onclick = function () { /*do stuff here */ };

... est l'équivalent du javascript en ligne, sauf que vous avez plus de contrôle sur la portée (puisque vous écrivez un script plutôt que du HTML) et que vous pouvez utiliser des fonctions anonymes, des références de fonctions et/ou des fermetures.

L'inconvénient majeur des événements en ligne est que, contrairement aux écouteurs d'événements décrits ci-dessus, un seul événement en ligne peut être attribué. Les événements en ligne sont stockés en tant qu'attribut/propriété de l'élément[ doc ], ce qui signifie qu'il peut être écrasé.

En utilisant l'exemple <a> du HTML ci-dessus :

var element = document.getElementById('testing');
element.onclick = function () { alert('did stuff #1'); };
element.onclick = function () { alert('did stuff #2'); };

... quand vous cliquez sur l'élément, vous avez sólo voir "Fait des trucs #2" - vous avez écrasé la première assignation de la onclick avec la deuxième valeur, et vous avez écrasé la propriété HTML en ligne d'origine. onclick la propriété aussi. Regardez ici : http://jsfiddle.net/jpgah/ .

De manière générale, ne pas utiliser les événements en ligne . Il peut y avoir des cas d'utilisation spécifiques pour cela, mais si vous n'êtes pas sûr à 100% d'avoir ce cas d'utilisation, alors vous ne devez pas utiliser les événements en ligne.

Javascript moderne (Angular et autres)

Depuis que cette réponse a été publiée, les frameworks javascript comme Angular sont devenus beaucoup plus populaires. Vous verrez du code comme celui-ci dans un modèle Angular :

<button (click)="doSomething()">Do Something</button>

Cela ressemble à un événement en ligne, mais ce n'est pas le cas. Ce type de modèle sera transposé dans du code plus complexe qui utilise des écouteurs d'événements dans les coulisses. Tout ce que j'ai écrit ici sur les événements reste valable, mais vous êtes éloigné des détails d'au moins une couche. Vous devez comprendre les rouages, mais si les meilleures pratiques de votre framework JS moderne impliquent d'écrire ce type de code dans un template, n'ayez pas l'impression d'utiliser un événement inline - ce n'est pas le cas.

Quelle est la meilleure solution ?

La question est une question de compatibilité des navigateurs et de nécessité. Avez-vous besoin d'attacher plus d'un événement à un élément ? Le ferez-vous à l'avenir ? Il y a de fortes chances que oui. attachEvent et addEventListener sont nécessaires. Si ce n'est pas le cas, un événement en ligne peut sembler faire l'affaire, mais il vaut mieux se préparer à un avenir qui, même s'il semble improbable, est au moins prévisible. Il est possible que vous deviez passer à des écouteurs d'événements basés sur JS, alors autant commencer par là. N'utilisez pas d'événements en ligne.

jQuery et d'autres frameworks javascript encapsulent les implémentations des différents navigateurs des événements de niveau 2 du DOM dans des modèles génériques afin que vous puissiez écrire un code compatible avec tous les navigateurs sans avoir à vous soucier de l'histoire d'IE comme rebelle. Le même code avec jQuery, compatible avec tous les navigateurs et prêt à fonctionner :

$(element).on('click', function () { /* do stuff */ });

Mais ne vous précipitez pas pour acheter un framework juste pour cette raison. Vous pouvez facilement créer votre propre petit utilitaire pour prendre en charge les anciens navigateurs :

function addEvent(element, evnt, funct){
  if (element.attachEvent)
   return element.attachEvent('on'+evnt, funct);
  else
   return element.addEventListener(evnt, funct, false);
}

// example
addEvent(
    document.getElementById('myElement'),
    'click',
    function () { alert('hi!'); }
);

Essayez-le : http://jsfiddle.net/bmArj/

En prenant tout cela en considération, à moins que le script que vous regardez n'ait pris en compte les différences entre les navigateurs d'une autre manière (dans un code qui n'est pas montré dans votre question), la partie qui utilise addEventListener ne fonctionnerait pas dans les versions d'IE inférieures à 9.

Documentation et lectures connexes

0 votes

Merci. J'ai vérifié le vôtre comme réponse et pour référence future. Merci d'avoir mentionné jQuery, car c'est la SOLUTION à mon problème.

0 votes

Il existe un ancien script pour la gestion des événements qui gère la différence entre les anciennes versions d'IE et les autres navigateurs : dean.edwards.name/weblog/2005/10/add-event2

16 votes

Désolé de relancer mais je voulais juste donner une version condensée de votre fonction (fiddle : jsfiddle.net/bmArj/153) - function addEvent(element, myEvent, fnc) { return ((element.attachEvent) ? element.attachEvent('on' + myEvent, fnc) : element.addEventListener(myEvent, fnc, false)); }

287voto

lonesomeday Points 95456

La différence que vous pourriez voir si vous aviez un autre couple de fonctions :

var h = document.getElementById('a');
h.onclick = doThing_1;
h.onclick = doThing_2;

h.addEventListener('click', doThing_3);
h.addEventListener('click', doThing_4);

Les fonctions 2, 3 et 4 fonctionnent, mais la 1 ne fonctionne pas. Cela est dû au fait que addEventListener ne remplace pas les gestionnaires d'événements existants, alors que onclick remplace tout gestionnaire d'événements onclick = fn existant.

L'autre différence significative, bien entendu, est que onclick fonctionnera toujours, alors que addEventListener ne fonctionne pas dans Internet Explorer avant la version 9. Vous pouvez utiliser l'équivalent attachEvent (qui a une syntaxe légèrement différente) dans IE <9.

29 votes

C'est une explication très claire! Directe au point. Donc, si j'ai besoin de plusieurs fonctions pour un événement, je suis coincé avec addEventListener, et je dois écrire plus de code pour attachEvent juste pour accommoder IE.

7 votes

2, 3 et 4 devraient être nommés dosomething. 1 est remplacé par 2 et n'est jamais appelé.

0 votes

En effet, une explication très claire et concise. Que ce serait en effet beaucoup plus logique de nommer les fonctions 'doThing_1', etc. (Si vous voulez toujours prendre en charge IE<9, voir la réponse de Chris.)

32voto

Magnar Points 15142

Alors que onclick fonctionne dans tous les navigateurs, addEventListener ne fonctionne pas dans les anciennes versions d'Internet Explorer, qui utilise attachEvent à la place.

L'inconvénient de onclick est qu'il ne peut y avoir qu'un seul gestionnaire d'événement, tandis que les deux autres déclencheront tous les rappels enregistrés.

12voto

jAndy Points 93076

D'après ce que je sais, l'événement DOM "load" ne fonctionne toujours que de manière très limitée. Cela signifie qu'il ne se déclenchera que pour l'objet window, les images et les éléments </code> par exemple. Il en va de même pour l'affectation directe de <code>onload</code>. Il n'y a pas de différence technique entre les deux. Probablement <code>.onload =</code> a une meilleure disponibilité multi-navigateurs.</p> <p>Cependant, vous ne pouvez pas attribuer un <code>événement de chargement</code> à un élément <code><div></code> ou <code><span></code> ou autre.</p></x-turndown>

1voto

Lars Rönnbäck Points 36

Si vous ne vous souciez pas trop du support du navigateur, il existe un moyen de réaffecter la référence 'this' dans la fonction appelée par l'événement. En général, cela pointera vers l'élément qui a généré l'événement lorsque la fonction est exécutée, ce qui n'est pas toujours ce que vous voulez. La partie délicate est de pouvoir en même temps supprimer ce même écouteur d'événement, comme le montre cet exemple : http://jsfiddle.net/roenbaeck/vBYu3/

/*
    Testez que la fonction retournée par bind est référençable de nouveau, 
    de telle sorte qu'elle puisse être ajoutée et supprimée en tant qu'écouteur d'événement.
*/
function MyImportantCalloutToYou(message, otherMessage) {
    // ce qui suit est nécessaire car appeler bind à nouveau ne renvoie 
    // pas la même fonction, donc nous remplaçons plutôt la 
    // fonction originale par celle liée à cette instance
    this.swap = this.swap.bind(this); 
    this.element = document.createElement('div');
    this.element.addEventListener('click', this.swap, false);
    document.body.appendChild(this.element);
}
MyImportantCalloutToYou.prototype = {
    element: null,
    swap: function() {
        // maintenant cette fonction peut être correctement supprimée 
        this.element.removeEventListener('click', this.swap, false);           
    }
}

Le code ci-dessus fonctionne bien dans Chrome, et il y a probablement un ajout pour rendre "bind" compatible avec d'autres navigateurs.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X