Question 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 distinct, et les deux fonctionnent parfaitement.


508
2018-06-14 18:49


origine


Réponses:


Les deux sont corrects, mais aucun d'entre eux n'est le «meilleur» en soi, et il peut y avoir une raison pour laquelle le développeur a choisi d'utiliser les deux approches.

Auditeurs d'événements (addEventListener et attachEvent d'IE)

Les versions antérieures d'Internet Explorer implémentent javascript différemment de pratiquement tous les autres navigateurs. Avec les versions inférieures à 9, vous utilisez le attachEvent[doc] méthode, comme ceci:

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

Dans la plupart des autres navigateurs (y compris IE 9 et ci-dessus), vous utilisez addEventListener[doc], comme ça:

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

En utilisant cette approche (Événements DOM niveau 2), vous pouvez attacher un nombre théoriquement illimité d'événements à un seul élément. La seule limitation 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énement 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 paramètre final, qui contrôle la façon dont l'auditeur réagit aux événements bouillonnants [doc] J'ai passé faux dans les exemples, ce qui est standard pour probablement 95% des cas d'utilisation. Il n'y a pas d'argument équivalent pour attachEventou lors de l'utilisation d'événements en ligne

Evénements en ligne (HTML onclick = "" property et element.onclick)

Dans tous les navigateurs qui prennent en charge javascript, vous pouvez mettre 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>

Les développeurs les plus expérimentés évitent cette méthode, mais le travail est fait. c'est simple et direct. Vous ne pouvez pas utiliser les fonctions de fermeture ou les fonctions anonymes ici (bien que le gestionnaire lui-même soit une sorte de fonction anonyme), 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 pouvez utiliser des fonctions anonymes, des références de fonction 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, vous ne pouvez avoir qu'un seul événement en ligne. 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'); };

... lorsque vous avez cliqué sur l'élément, vous auriez seulement voir "Did stuff # 2" - vous avez écrasé le premier assigné du onclick propriété avec la deuxième valeur, et vous avez écrasé le HTML en ligne d'origine onclick propriété aussi. Vérifiez le ici: http://jsfiddle.net/jpgah/.

Quel est le meilleur?

La question est une question de compatibilité et de nécessité du navigateur. Avez-vous actuellement besoin d'associer plus d'un événement à un élément? Voulez-vous dans le futur? Les chances sont, vous le ferez. attachEvent et addEventListener sont nécessaires. Sinon, un événement en ligne fera l'affaire.

jQuery et d'autres frameworks javascript encapsulent les différentes implémentations de navigateur d'événements DOM niveau 2 dans des modèles génériques, ce qui vous permet d'écrire du code compatible avec plusieurs navigateurs sans avoir à vous soucier de l'historique d'IE en tant que rebelle. Même code avec jQuery, tous cross-browser et prêt à basculer:

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

Ne t'enfuis pas et n'obtiens pas un cadre juste pour cette chose, cependant. Vous pouvez facilement lancer votre propre petit utilitaire pour prendre soin des 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/

Prenant tout cela en considération, à moins que le script que vous regardez ait pris en compte les différences du navigateur d'une autre manière (dans le code non montré dans votre question), la partie utilisant addEventListener ne fonctionnerait pas dans les versions IE inférieures à 9.

Documentation et lecture connexe


728
2018-06-14 18:59



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 pas 1. Ceci est dû au fait addEventListener ne remplace pas les gestionnaires d'événements existants, alors que onclick remplace tout existant onclick = fn gestionnaires d'événements.

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


128
2018-06-14 18:52



Dans cette réponse, je vais décrire les trois méthodes de définition des gestionnaires d'événements DOM.

element.addEventListener()

Exemple de code:

const element = document.querySelector('a');
element.addEventListener('click', event => event.preventDefault(), true);
<a href="//google.com">Try clicking this link.</a>

element.addEventListener() a de multiples avantages:

  • Vous permet de vous inscrire illimité gestionnaires d'événements et les supprimer avec element.removeEventListener().
  • A useCapture paramètre, qui indique si vous souhaitez gérer l'événement dans son phase de capture ou de bullage. Voir: Impossible de comprendre l'attribut useCapture dans addEventListener.
  • Se soucie de sémantique. Fondamentalement, cela rend l'enregistrement des gestionnaires d'événements plus explicite. Pour un débutant, un appel de fonction rend évident que quelque chose arrive, alors que l'assignation d'un événement à une propriété de l'élément DOM est au moins non intuitive.
  • Te permet de structure de document séparée (HTML) et logique (JavaScript). Dans les applications Web minuscules, cela peut ne pas sembler important, mais Est-ce que importe avec un plus gros projet. Il est beaucoup plus facile de maintenir un projet qui sépare la structure et la logique qu'un projet qui ne le fait pas.
  • Élimine la confusion avec les noms d'événements corrects. En raison de l'utilisation d'auditeurs d'événements en ligne ou de l'affectation d'auditeurs d'événements à .onevent propriétés des éléments DOM, beaucoup de programmeurs JavaScript inexpérimentés pense que le nom de l'événement est par exemple onclick ou onload. on est ne pas une partie du nom de l'événement. Les noms d'événement corrects sont click et load, et comment les noms des événements sont passés à .addEventListener().
  • Travaille dans presque tous les navigateurs. Si vous devez toujours prendre en charge IE <= 8, vous pouvez utiliser un polyfill de MDN.

element.onevent = function() {} (par exemple. onclick, onload)

Exemple de code:

const element = document.querySelector('a');
element.onclick = event => event.preventDefault();
<a href="//google.com">Try clicking this link.</a>

C'était un moyen d'enregistrer des gestionnaires d'événements dans DOM 0. Il est maintenant déconseillé, car:

  • Vous permet de vous inscrire seulement un gestionnaire d'événements. La suppression du gestionnaire attribué n’est pas non plus intuitive, car pour supprimer le gestionnaire d’événement affecté à l’aide de cette méthode, vous devez rétablir onevent propriété de retour à son état initial (c'est-à-dire null).
  • Ne pas répondre aux erreurs de manière appropriée. Par exemple, si vous attribuez par erreur une chaîne à window.onload, par exemple: window.onload = "test";, il ne jettera aucune erreur. Votre code ne fonctionnerait pas et il serait vraiment difficile de savoir pourquoi. .addEventListener() cependant, lancerait une erreur (au moins dans Firefox): TypeError: L'argument 2 de EventTarget.addEventListener n'est pas un objet.
  • Ne fournit pas un moyen de choisir si vous voulez gérer un événement dans sa phase de capture ou de bouillonnement.

Les gestionnaires d'événements en ligne (onevent Attribut HTML)

Exemple de code:

<a href="//google.com" onclick="event.preventDefault();">Try clicking this link.</a>

Similaire à element.onevent, il est maintenant découragé. Outre les problèmes qui element.onevent a-t-il:

  • Est un problème de sécurité potentiel, car cela rend le XSS beaucoup plus dangereux. De nos jours, les sites Web doivent envoyer correctement Content-Security-Policy En-tête HTTP pour bloquer les scripts en ligne et autoriser les scripts externes uniquement à partir de domaines approuvés. Voir Comment fonctionne la politique de sécurité du contenu?
  • Ne pas structure de document séparée et logique.
  • Si vous générez votre page avec un script côté serveur et que vous générez par exemple une centaine de liens, chacun avec le même gestionnaire d'événement en ligne, votre code sera beaucoup plus long que si le gestionnaire d'événement n'était défini qu'une seule fois. Cela signifie que le client devra télécharger plus de contenu, et en conséquence, votre site Web sera plus lent.

Voir également


43
2018-01-29 21:01



Tandis que onclick fonctionne dans tous les navigateurs, addEventListener ne fonctionne pas dans les anciennes versions d'Internet Explorer, qui utilise attachEvent au lieu.

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


16
2018-06-14 18:52



Pour autant que je sache, l'événement DOM "load" ne fonctionne que très peu. Cela signifie que ça ne fera que tirer pour le window object, images et <script> éléments par exemple. La même chose vaut pour le direct onload affectation. Il n'y a pas de différence technique entre les deux. Probablement .onload = a une meilleure disponibilité de navigateur croisé.

Cependant, vous ne pouvez pas affecter un load event à un <div> ou <span> élément ou autre.


12
2017-08-01 17:27



Si vous n'êtes pas trop préoccupé par la prise en charge du navigateur, il existe un moyen de relier la référence "this" dans la fonction appelée par l'événement. Il pointe normalement 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 la plus délicate consiste à supprimer simultanément le même écouteur d'événement, comme illustré dans cet exemple: http://jsfiddle.net/roenbaeck/vBYu3/

/*
    Testing that the function returned from bind is rereferenceable, 
    such that it can be added and removed as an event listener.
*/
function MyImportantCalloutToYou(message, otherMessage) {
    // the following is necessary as calling bind again does 
    // not return the same function, so instead we replace the 
    // original function with the one bound to this 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() {
        // now this function can be properly removed 
        this.element.removeEventListener('click', this.swap, false);           
    }
}

Le code ci-dessus fonctionne bien dans Chrome, et il y a probablement de la place pour rendre "bind" compatible avec les autres navigateurs.


1
2018-03-14 09:36



L'utilisation de gestionnaires en ligne est incompatible avec Politique de sécurité du contenu alors le addEventListener l'approche est plus sûre de ce point de vue. Bien sûr, vous pouvez activer les gestionnaires en ligne avec unsafe-inline mais, comme son nom l'indique, il n'est pas sûr car il ramène l'ensemble des hordes d'exploits JavaScript que CSP empêche.


1
2018-04-20 16:40



Un détail n'a pas encore été noté: les navigateurs de bureau modernes considèrent différentes pressions sur les boutons comme des "clics" pour AddEventListener('click' et onclick par défaut.

  • Sur Chrome 42 et IE11, les deux onclick et AddEventListener cliquez sur le feu à gauche et le clic du milieu.
  • Sur Firefox 38, onclick les feux seulement sur le clic gauche, mais AddEventListener cliquez sur les feux à gauche, au milieu et clics droits.

En outre, le comportement de clic central est très incohérent entre les navigateurs lorsque les curseurs de défilement sont impliqués:

  • Sur Firefox, les événements de clic intermédiaire sont toujours déclenchés.
  • Sur Chrome, ils ne se déclencheront pas si le paramètre middleclick ouvre ou ferme un curseur de défilement.
  • Sur IE, ils se déclenchent lorsque le curseur de défilement se ferme, mais pas à l'ouverture.

Il est également intéressant de noter que les événements "click" pour tout élément HTML sélectionnable au clavier tel que input également tirer sur l'espace ou entrer lorsque l'élément est sélectionné.


1
2018-06-30 19:30