Comment fonctionne plusieurs addEventListener en JavaScript?

Il existe 2 scripts dans un document

// my_script.js goes first document.onclick = function() { alert("document clicked"); }; // other_script.js comes after // this overrides the onclick of my script, // and alert will NOT be fired document.onclick = function() { return false; }; 

Pour s'assurer que mon événement de clic ne soit pas remplacé par un autre script, j'ai changé pour addEventListener .

 // my_script.js goes first document.addEventListener("click", function() { alert("document clicked"); }, false); // other_script.js comes after document.addEventListener("click", function() { return false; }, false); 

Maintenant, j'ai une autre question. Puisque le return false dans le deuxième code est défini après l' alert , comment se fait-il qu'il n'empêche pas que l'alerte ne soit appelée?

Et si je veux que mon script obtienne un contrôle total de l'événement de clic (comme renvoyer tout le temps en évitant les événements définis dans d'autres scripts)?

Et si je veux que mon script obtienne un contrôle total de l'événement de clic (comme renvoyer tout le temps en évitant les événements définis dans d'autres scripts)?

Si vous pouvez d'abord enregistrer votre gestionnaire, avant de le faire, vous pouvez le faire, pourvu que le navigateur que vous utilisez implémente correctement les événements DOM3 (ce qui est probablement le cas si ce n'est IE8 ou plus tôt).

Il y a (au moins) quatre choses impliquées ici:

  1. Prévention de la valeur par défaut.

  2. Arrêt de la propagation aux éléments ancêtres.

  3. Arrêt d'appeler les autres gestionnaires sur le même élément.

  4. L'ordre dans lequel les gestionnaires sont appelés.

En ordre:

1. Prévenir le défaut

C'est ce que return false d'un gestionnaire DOM0. (Détails: The Story on Return False .) L'équivalent dans DOM2 et DOM3 est preventDefault :

 document.addEventListener("click", function(e) { e.preventDefault(); }, false); 

Prévenir la valeur par défaut peut ne pas être tout pertinent pour ce que vous faites, mais comme vous utilisiez le return false dans votre gestionnaire DOM0, et cela empêche la valeur par défaut, je l'inclue ici pour être exhaustif.

2. Arrêt de la propagation aux éléments ancêtres

Les gestionnaires DOM0 n'ont aucun moyen de le faire. DOM2, via stopPropagation :

 document.addEventListener("click", function(e) { e.stopPropagation(); }, false); 

Mais stopPropagation n'arrête pas les autres manipulateurs sur ce même élément appelé. À partir de la spécification :

La méthode stopPropagation est utilisée pour empêcher la propagation ultérieure d'un événement pendant le flux d'événements. Si cette méthode est appelée par n'importe quel EventListener l'événement cessera de se propager dans l'arborescence. L'événement terminera l'envoi à tous les auditeurs sur l' EventTarget actuel avant que le flux d'événement ne s'arrête.

(Mon accent.)

3. Arrêt d'appeler d'autres gestionnaires sur le même élément

Naturellement, il ne s'agissait pas de DOM0, car il ne pouvait y avoir d' autres gestionnaires pour le même événement sur le même élément. 🙂

Pour autant que je sache, il n'y a aucun moyen de le faire dans DOM2, mais DOM3 nous donne stopImmediatePropagation :

 document.addEventListener("click", function(e) { e.stopImmediatePropagation(); }, false); 

Certaines bibliothèques offrent cette fonctionnalité (même sur des systèmes non DOM3 comme IE8) pour les gestionnaires branchés via la bibliothèque, voir ci-dessous.

4. L'ordre dans lequel les gestionnaires sont appelés

Encore une fois, pas quelque chose qui concernait DOM0, car il ne pouvait y avoir d'autres gestionnaires.

Dans DOM2, la spécification indique explicitement que l'ordre dans lequel les gestionnaires attachés à un élément est appelé n'est pas garanti; Mais DOM3 change, disant que les gestionnaires sont appelés dans l'ordre dans lequel ils sont enregistrés.

D'abord, de DOM2 Section 1.2.1 :

Bien que tous les EventListeners sur EventTarget soient EventTarget à être déclenchés par n'importe quel événement qui est reçu par cette EventTarget , aucune spécification n'est faite quant à l'ordre dans lequel ils recevront l'événement en ce qui concerne les autres EventListeners sur EventTarget .

Mais cela est remplacé par DOM3 Section 3.1 :

Ensuite, la mise en œuvre doit déterminer les auditeurs de l'événement candidat de la cible actuelle. Ce doit être la liste de tous les auditeurs d'événements qui ont été enregistrés sur la cible actuelle dans leur ordre d'inscription .

(Mon accent.)

Certaines bibliothèques garantissent la commande, à condition de brancher les événements avec la bibliothèque.

Il est également intéressant de noter que, dans le prédécesseur de Microsoft de DOM2 (par exemple, attachEvent ), c'est l'inverse de l'ordre de DOM3: les gestionnaires ont été appelés dans l' ordre inverse de l'enregistrement.


Donc, en prenant # 3 et # 4 ensemble, si vous pouvez d'abord enregistrer votre gestionnaire, il sera appelé en premier et vous pouvez utiliser stopImmediatePropagation pour éviter d'autres appelants. À condition que le navigateur implémente correctement DOM3.


Tout cela (y compris le fait que IE8 et versions antérieures n'impliquent même pas les événements DOM2, beaucoup moins DOM3) est une des raisons pour lesquelles les gens utilisent des bibliothèques comme jQuery, dont certaines garantissent l'ordre (tant que tout est en train de raccorder leurs gestionnaires via La bibliothèque en question) et offre des moyens d'arrêter même d'autres gestionnaires sur le même élément appelé. (Avec jQuery, par exemple, l'ordre est l'ordre dans lequel ils ont été joints, et vous pouvez utiliser stopImmediatePropagation pour arrêter les appels à d'autres gestionnaires. Mais je n'essaie pas de vendre jQuery ici, en expliquant simplement que certaines libs offrent plus de fonctionnalités que Les choses DOM de base.)