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 dans un fichier .js séparé et ils fonctionnent parfaitement.
Les deux sont corrects, mais aucun d'entre eux n'est "meilleur" en soi, et il peut y avoir une raison pour laquelle le développeur a choisi d'utiliser les deux approches.
Écouteurs d'événement (addEventListener et l'attachement d'IE)
Les versions précédentes d'Internet Explorer implémentent le javascript différemment de presque tous les autres navigateurs. Avec les versions inférieures à 9, vous utilisez la méthode attachEvent
[ doc ], comme ceci:
element.attachEvent('onclick', function() { /* do stuff here*/ });
Dans la plupart des autres navigateurs (y compris IE 9 et versions ultérieures), vous utilisez addEventListener
[ doc ], comme suit:
element.addEventListener('click', function() { /* do stuff here*/ }, false);
En utilisant cette approche ( événements DOM niveau 2 ), vous pouvez attacher un nombre d’événements théoriquement illimité à un seul élément. La seule limite pratique concerne la mémoire côté client et d'autres problèmes de performances, 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 à l'aide d'une référence de fonction [ doc ] ou d'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 réaction de l'écouteur aux événements de propagation [ doc ]. J'ai passé faux dans les exemples, ce qui est la norme 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.
Evénements en ligne (HTML onclick = "" propriété et element.onclick)
Dans tous les navigateurs prenant en charge javascript, vous pouvez insérer 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 évitent cette méthode, mais le travail est fait; c'est simple et direct. Vous ne pouvez pas utiliser de fermetures ou de fonctions anonymes ici (bien que le gestionnaire lui-même soit une 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 */ };
... équivaut au javascript en ligne, sauf que vous maîtrisez mieux la portée (puisque vous écrivez un script plutôt que 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 remplacé.
En utilisant l'exemple <a>
du code 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 seulement voyez "Did stuff # 2" - vous avez écrasé le premier assigné de la onclick
propriété avec la deuxième valeur et vous avez écrasé la propriété inline HTML onclick
originale également. Découvrez-le ici: http://jsfiddle.net/jpgah/ .
De manière générale, n'utilise pas d'événements en ligne . Il peut y avoir des cas d'utilisation spécifiques, mais si vous n'êtes pas sûr à 100% que vous avez ce cas d'utilisation, vous ne devez pas et ne devriez pas utiliser d'événements en ligne.
Javascript moderne (angulaire, etc.)
Depuis que cette réponse a été publiée, les frameworks javascript tels que Angular sont devenus beaucoup plus populaires. Vous verrez un 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. Ce type de modèle sera transpilé en un code plus complexe qui utilise des écouteurs d'événements en coulisse. Tout ce que j'ai écrit sur les événements ici s'applique toujours, mais vous êtes éliminé du fond des choses au moins une couche. Vous devez comprendre les rouages de base, mais si vos meilleures pratiques en matière de framework JS moderne impliquent l'écriture de ce type de code dans un modèle, n'ayez pas l'impression d'utiliser un événement en ligne - vous ne l'êtes pas.
Quel est le meilleur?
La question est une question de compatibilité et de nécessité du navigateur. Avez-vous actuellement besoin d'attacher plus d'un événement à un élément? Veux-tu dans le futur? Les chances sont, vous allez. attachEvent et addEventListener sont nécessaires. Si ce n'est pas le cas, un événement en ligne peut sembler être la solution, mais vous êtes bien mieux préparé à un avenir qui, bien que cela puisse paraître improbable, est au moins prévisible. Il est possible que vous deviez passer aux écouteurs d'événements basés sur JS. Vous pouvez donc également commencer par là. Ne pas utiliser les événements en ligne.
jQuery et d'autres frameworks javascript encapsulent les différentes implémentations de navigateur des événements DOM de niveau 2 dans les modèles génériques afin que vous puissiez écrire du code compatible entre navigateurs sans vous soucier de l'historique d'IE en tant que rebelle. Même code avec jQuery, tous navigateurs croisés et prêt à basculer:
$(element).on('click', function () { /* do stuff */ });
Ne vous précipitez pas et obtenez un cadre pour cette seule chose, cependant. Vous pouvez facilement lancer 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/
Compte tenu de tout cela, à moins que le script que vous êtes en train de regarder prenne en compte les différences de navigateur d'une autre manière (en code non indiqué dans votre question), la partie utilisant addEventListener
ne fonctionnerait pas dans IE versions inférieures à 9.
Documentation et lectures associées
La différence que vous pourriez voir si vous aviez deux autres 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 1 ne fonctionne pas. En effet, addEventListener
n'écrase pas les gestionnaires d'événements existants, alors que onclick
remplace tous les gestionnaires d'événements onclick = fn
existants.
L’autre différence significative, bien sûr, est que onclick
fonctionnera toujours, alors que addEventListener
ne fonctionnera pas dans Internet Explorer avant la version 9. Vous pouvez utiliser l’analogue attachEvent
(qui - légèrement syntaxe différente) dans IE <9.
Dans cette réponse, je décrirai 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()
présente de nombreux avantages:
element.removeEventListener()
.useCapture
, qui indique si vous souhaitez gérer un événement dans sa phase de capture ou de formation de bulles . Voir: Incapable de comprendre l'attribut useCapture dans addEventListener ..onevent
des éléments DOM, de nombreux programmeurs JavaScript inexpérimentés pensent que le nom de l'événement est par exemple onclick
ou onload
. on
est not une partie du nom de l'événement . Les noms d'événements corrects sont click
et load
, et c'est ainsi que les noms d'événements sont passés à .addEventListener()
.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 une façon d'enregistrer les gestionnaires d'événements dans DOM 0. C'est maintenant déconseillé, parce que:
onevent
à son état initial (c'est-à-dire null
).window.onload
, par exemple: window.onload = "test";
, aucune erreur ne sera générée. Votre code ne fonctionnerait pas et il serait très difficile de savoir pourquoi. .addEventListener()
cependant, émettrait une erreur (au moins dans Firefox): TypeError: l'argument 2 de EventTarget.addEventListener n'est pas un objet.onevent
HTML)Exemple de code:
<a href="//google.com" onclick="event.preventDefault();">Try clicking this link.</a>
De la même manière que element.onevent
, il est maintenant déconseillé. Outre les problèmes que element.onevent
a, il:
Content-Security-Policy
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?Alors que onclick
fonctionne dans tous les navigateurs, addEventListener
ne fonctionne pas dans les versions antérieures 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énements, tandis que les deux autres déclenchent tous les rappels enregistrés.
Autant que je sache, l'événement "load" du DOM ne fonctionne toujours que de manière très limitée. Cela signifie qu'il ne sera déclenché que pour les éléments window object
, images
et <script>
, par exemple. Il en va de même pour l'affectation directe onload
. Il n'y a pas de différence technique entre ces deux. Probablement .onload =
a une meilleure disponibilité entre navigateurs.
Cependant, vous ne pouvez pas affecter un load event
à un élément <div>
ou <span>
ou quoi encore.
addEventListener
peut ajouter plusieurs événements, alors qu'avec onclick
cela ne peut pas être fait.onclick
peut être ajouté en tant qu'attribut HTML
, alors qu'un addEventListener
ne peut être ajouté qu'à l'intérieur de <script>
éléments.addEventListener
peut prendre un troisième argument qui peut arrêter la propagation de l'événement.Les deux peuvent être utilisés pour gérer des événements. Cependant, addEventListener
devrait être le choix préféré, car il peut tout faire onclick
fait et plus encore. N'utilisez pas onclick
inline en tant qu'attributs HTML, car cela mélange le javascript et le HTML, ce qui est une mauvaise pratique. Cela rend le code moins facile à gérer.
Selon MDN, la différence est la suivante:
addEventListener:
La méthode EventTarget.addEventListener () ajoute l'objet compatible EventListener spécifié à la liste des écouteurs d'événement pour le type d'événement spécifié sur le EventTarget sur lequel il est appelé. La cible d'événement peut être un élément d'un document, le document lui-même, une fenêtre ou tout autre objet prenant en charge des événements (tel que XMLHttpRequest).
onclick:
La propriété onclick renvoie le code du gestionnaire d'événements click sur l'élément actuel. Lorsque vous utilisez l'événement click pour déclencher une action, envisagez également d'ajouter cette même action à l'événement keydown, afin de permettre à cette même action d'être utilisée par des personnes qui n'utilisent pas de souris ou d'écran tactile. Syntaxe element.onclick = functionRef; où functionRef est une fonction - souvent le nom d'une fonction déclarée ailleurs ou une expression de fonction. Voir "Guide JavaScript: Fonctions" pour plus de détails.
Il existe également une différence de syntaxe d'utilisation, comme vous le voyez dans les codes ci-dessous:
addEventListener:
// Function to change the content of t2
function modifyText() {
var t2 = document.getElementById("t2");
if (t2.firstChild.nodeValue == "three") {
t2.firstChild.nodeValue = "two";
} else {
t2.firstChild.nodeValue = "three";
}
}
// add event listener to table
var el = document.getElementById("outside");
el.addEventListener("click", modifyText, false);
onclick:
function initElement() {
var p = document.getElementById("foo");
// NOTE: showAlert(); or showAlert(param); will NOT work here.
// Must be a reference to a function name, not a function call.
p.onclick = showAlert;
};
function showAlert(event) {
alert("onclick Event detected!");
}
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.
onclick
et AddEventListener
vous permettent de cliquer sur les boutons Clic gauche et moyen.onclick
déclenche niquement lors d'un clic gauche, mais AddEventListener
un clic se déclenche lors d'un clic gauche, au centre et.De plus, le comportement du clic du milieu est très incohérent entre les navigateurs lorsque des curseurs de défilement sont impliqués:
Il est également intéressant de noter que les événements de "clic" pour tout élément HTML sélectionnable au clavier, tel que input
, se déclenchent également dans l'espace ou entrent lorsque l'élément est sélectionné.
Si le support du navigateur ne vous inquiète pas trop, il existe un moyen de relier la référence "this" dans la fonction appelée par l'événement. Il indiquera normalement 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 consiste à pouvoir en même temps supprimer le même écouteur d'événement, comme indiqué 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 quelques difficultés à rendre "bind" compatible avec les autres navigateurs.
Il devrait également être possible d'étendre l'auditeur en le prototypant (si nous avons une référence à cette fonction et que ce n'est pas une fonction anonyme) ou de faire l'appel 'onclick' à une bibliothèque de fonctions (une fonction appelant d'autres fonctions).
comme
Elm.onclick = myFunctionList
function myFunctionList(){
myFunc1();
myFunc2();
}
cela signifie que nous n'avons jamais à modifier l'appel de onclick, mais simplement à modifier la fonction myFunctionList () pour faire ce que nous voulons, mais cela nous laisse sans contrôle des phases de barbotage/capture et doit donc être évité pour les nouveaux navigateurs.
juste au cas où quelqu'un trouverait ce fil dans le futur ...
L'utilisation de gestionnaires en ligne est incompatible avec stratégie de sécurité du conten , de sorte que l'approche addEventListener
est plus sécurisée de ce point de vue. Bien sûr, vous pouvez activer les gestionnaires en ligne avec unsafe-inline
mais, comme son nom l’indique, ce n’est pas sans danger, car cela ramène toutes les exploitations JavaScript que CSP empêche.
Le contexte référencé par le mot clé 'this'
dans JavasSript est différent.
regardez le code suivant:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
</head>
<body>
<input id="btnSubmit" type="button" value="Submit" />
<script>
function disable() {
this.disabled = true;
}
var btnSubmit = document.getElementById('btnSubmit');
btnSubmit.onclick = disable();
//btnSubmit.addEventListener('click', disable, false);
</script>
</body>
</html>
Ce qu'il fait est vraiment simple. lorsque vous cliquez sur le bouton, le bouton sera automatiquement désactivé.
D'abord, lorsque vous essayez de connecter les événements de cette façon, button.onclick = function(),
l'événement onclick sera déclenché en cliquant sur le bouton. Toutefois, le bouton ne sera pas désactivé car il n'y a pas de liaison explicite entre button.onclick et le gestionnaire d'événements onclick. Si vous déboguez voir l'objet 'this'
, vous pouvez voir qu'il fait référence à l'objet 'window'
.
Deuxièmement, si vous commentez btnSubmit.onclick = disable();
et décommentez //btnSubmit.addEventListener('click', disable, false);
, vous pouvez voir que le bouton est désactivé car, de cette manière, il existe une liaison explicite entre les événements button.onclick et le gestionnaire d'événements onclick. Si vous déboguez dans la fonction de désactivation, vous pouvez voir que 'this'
désigne le button control
plutôt que le window
.
C'est quelque chose que je n'aime pas dans JavaScript, qui est une incohérence. Au fait, si vous utilisez jQuery ($('#btnSubmit').on('click', disable);
), il utilise une liaison explicite.
Javascript a tendance à tout mélanger dans des objets, ce qui peut prêter à confusion. Tout en un est la manière JavaScript.
Essentiellement onclick est un attribut HTML. Inversement, addEventListener est une méthode sur l'objet DOM représentant un élément HTML.
Dans les objets JavaScript, une méthode est simplement une propriété qui a une fonction en tant que valeur et qui est opposée à l'objet auquel elle est attachée (en utilisant ceci par exemple).
En JavaScript en tant qu'élément HTML représenté par DOM, ses attributs sont mappés sur ses propriétés.
C'est là que les gens sont déroutés, car JavaScript fusionne tout dans un conteneur ou un espace de noms unique, sans aucune couche d'indirection.
Dans une disposition normale OO (qui fusionne au moins l'espace de noms des propriétés/méthodes), vous pourriez avoir quelque chose comme:
domElement.addEventListener // Object(Method)
domElement.attributes.onload // Object(Property(Object(Property(String))))
Il existe des variantes, par exemple l'utilisation d'un getter/setter pour onload ou de HashMap pour les attributs, mais en fin de compte, il en serait de même. JavaScript a éliminé cette couche d'indirection au lieu de savoir quoi entre autres. Il a fusionné domElement et attributs.
Sauf compatibilité, vous devriez, comme meilleure pratique, utiliser addEventListener. Tandis que d’autres réponses parlent des différences à cet égard plutôt que des différences programmatiques fondamentales, je vais l’abandonner. Essentiellement, dans un monde idéal, vous ne devez utiliser que du * HTML, mais dans un monde encore plus idéal, vous ne devriez rien faire de semblable à partir de HTML.
Pourquoi est-il dominant aujourd'hui? C'est plus rapide à écrire, plus facile à apprendre et à travailler.
Le but principal de onload en HTML est de donner accès à la méthode ou à la fonctionnalité addEventListener en premier lieu. En l’utilisant dans JS, vous passez par HTML alors que vous pourriez l’appliquer directement.
Hypothétiquement, vous pouvez créer vos propres attributs:
$('[myclick]').each(function(i, v) {
v.addEventListener('click', function() {
eval(v.myclick); // eval($(v).attr('myclick'));
});
});
Ce que JS fait avec est un peu différent de cela.
Vous pouvez l'associer à quelque chose comme (pour chaque élément créé):
element.addEventListener('click', function() {
switch(typeof element.onclick) {
case 'string':eval(element.onclick);break;
case 'function':element.onclick();break;
}
});
Les détails de la mise en œuvre réelle différeront probablement avec une gamme de variations subtiles rendant les deux légèrement différents dans certains cas, mais c'est l'essentiel de celui-ci.
C'est sans doute un problème de compatibilité que vous pouvez épingler une fonction à un attribut sur puisque par défaut, les attributs sont toutes des chaînes.
addEventListener
vous permet de définir plusieurs gestionnaires, mais n'est pas pris en charge dans IE8 ou une version inférieure.
IE a attachEvent
, mais ce n'est pas exactement la même chose.