Comment trouver des auditeurs d'événements sur un nœud DOM lors du débogage ou du code JavaScript?

J'ai une page où certains auditeurs d'événements sont attachés aux boîtes de saisie et aux boîtes de sélection. Existe-t-il un moyen de savoir quel événement les auditeurs observent un noeud DOM particulier et pour quel événement?

Les événements sont joints en utilisant:

  1. Prototype's Event.observe ;
  2. DOM addEventListener ;
  3. En tant qu'élément d'élément, attribuez.

Si vous avez juste besoin d'inspecter ce qui se passe sur une page, vous pouvez essayer le bookmarklet Visual Event .

Mise à jour : Visual Event 2 disponible;

Cela dépend de la façon dont les événements sont joints. Pour présumer l'illustration, nous avons le gestionnaire de clic suivant:

 var handler = function() { alert('clicked!') }; 

Nous allons l'attacher à notre élément en utilisant différentes méthodes, certaines qui permettent l'inspection et celles qui n'en ont pas.

Méthode A) gestionnaire d'événement unique

 element.onclick = handler; // inspect alert(element.onclick); // alerts "function() { alert('clicked!') }" 

Méthode B) gestionnaires d'événements multiples

 if(element.addEventListener) { // DOM standard element.addEventListener('click', handler, false) } else if(element.attachEvent) { // IE element.attachEvent('onclick', handler) } // cannot inspect element to find handlers 

Méthode C): jQuery

 $(element).click(handler); 
  • 1.3.x

     // inspect var clickEvents = $(element).data("events").click; jQuery.each(clickEvents, function(key, value) { alert(value) // alerts "function() { alert('clicked!') }" }) 
  • 1.4.x (stocke le gestionnaire dans un objet)

     // inspect var clickEvents = $(element).data("events").click; jQuery.each(clickEvents, function(key, handlerObj) { alert(handlerObj.handler) // alerts "function() { alert('clicked!') }" // also available: handlerObj.type, handlerObj.namespace }) 

(Voir jQuery.fn.data et jQuery.data )

Méthode D): Prototype (désordonné)

 $(element).observe('click', handler); 
  • 1.5.x

     // inspect Event.observers.each(function(item) { if(item[0] == element) { alert(item[2]) // alerts "function() { alert('clicked!') }" } }) 
  • 1.6 à 1.6.0.3, inclusivement (a été très difficile ici)

     // inspect. "_eventId" is for < 1.6.0.3 while // "_prototypeEventID" was introduced in 1.6.0.3 var clickEvents = Event.cache[element._eventId || (element._prototypeEventID || [])[0]].click; clickEvents.each(function(wrapper){ alert(wrapper.handler) // alerts "function() { alert('clicked!') }" }) 
  • 1.6.1 (peu mieux)

     // inspect var clickEvents = element.getStorage().get('prototype_event_registry').get('click'); clickEvents.each(function(wrapper){ alert(wrapper.handler) // alerts "function() { alert('clicked!') }" }) 

Chrome, Firefox, Vivaldi et Safari supportent getEventListeners(domElement) dans leur console d'outils de développement.

Pour la plupart des fins de débogage, cela pourrait être utilisé.

Vous trouverez ci-dessous une très bonne référence pour l'utiliser: https://developers.google.com/chrome-developer-tools/docs/commandline-api#geteventlistenersobject

WebKit Inspector dans les navigateurs Chrome ou Safari fait maintenant cela. Il affichera les auditeurs d'événements pour un élément DOM lorsque vous le sélectionnez dans le volet Éléments.

Il est possible d'énumérer tous les auditeurs d'événements en JavaScript: ce n'est pas si difficile; Il suffit de pirater la méthode du prototype des éléments HTML ( avant d' ajouter les auditeurs).

 function reportIn(e){ var a = this.lastListenerInfo[this.lastListenerInfo.length-1]; console.log(a) } HTMLAnchorElement.prototype.realAddEventListener = HTMLAnchorElement.prototype.addEventListener; HTMLAnchorElement.prototype.addEventListener = function(a,b,c){ this.realAddEventListener(a,reportIn,c); this.realAddEventListener(a,b,c); if(!this.lastListenerInfo){ this.lastListenerInfo = new Array()}; this.lastListenerInfo.push({a : a, b : b , c : c}); }; 

Maintenant, chaque élément d'ancrage ( a ) aura une propriété lastListenerInfo qui contient tous ses auditeurs. Et cela fonctionne même pour éliminer les auditeurs avec des fonctions anonymes.

(Réécriture de la réponse de cette question puisqu'il est pertinent ici.)

Lors du débogage, si vous voulez juste voir les événements, je vous recommande …

  1. Événement visuel
  2. La section Elements des outils de développement de Chrome: sélectionnez un élément et recherchez "Écouter des auditeurs" en bas à droite (similaire à Firefox)

Si vous souhaitez utiliser les événements dans votre code et que vous utilisez jQuery avant la version 1.8 , vous pouvez utiliser:

 $(selector).data("events") 

Pour obtenir les événements. À partir de la version 1.8, l'utilisation de .data ("événements") est interrompue (voir ce ticket de bogue ). Vous pouvez utiliser:

 $._data(element, "events") 

Un autre exemple: Écrivez tous les événements de clic sur un certain lien vers la console:

 var $myLink = $('a.myClass'); console.log($._data($myLink[0], "events").click); 

(Voir http://jsfiddle.net/HmsQC/ pour un exemple de travail)

Malheureusement, en utilisant des données $ ._, cela n'est pas recommandé, sauf pour le débogage car il s'agit d'une structure jQuery interne, et pourrait changer dans les versions ultérieures. Malheureusement, je ne connais aucun autre moyen facile d'accéder aux événements.

1: Prototype.observe utilise Element.addEventListener (voir le code source )

2: Vous pouvez annuler Element.addEventListener pour vous souvenir des auditeurs ajoutés (la propriété EventListenerList été retirée de la proposition de spécification DOM3). Exécutez ce code avant qu'un événement ne soit joint:

 (function() { Element.prototype._addEventListener = Element.prototype.addEventListener; Element.prototype.addEventListener = function(a,b,c) { this._addEventListener(a,b,c); if(!this.eventListenerList) this.eventListenerList = {}; if(!this.eventListenerList[a]) this.eventListenerList[a] = []; this.eventListenerList[a].push(b); }; })(); 

Lisez tous les événements par:

 var clicks = someElement.eventListenerList.click; if(clicks) clicks.forEach(function(f) { alert("I listen to this function: "+f.toString()); }); 

Et n'oubliez pas de remplacer Element.removeEventListener pour supprimer l'événement de Element.eventListenerList personnalisé.

3: la propriété Element.onclick nécessite un soin particulier ici:

 if(someElement.onclick) alert("I also listen tho this: "+someElement.onclick.toString()); 

4: n'oubliez pas l'attribut Element.onclick contenu: il s'agit de deux choses différentes:

 someElement.onclick = someHandler; // IDL attribute someElement.setAttribute("onclick","otherHandler(event)"); // content attribute 

Donc, vous devez le gérer aussi:

 var click = someElement.getAttribute("onclick"); if(click) alert("I even listen to this: "+click); 

Le bookmarklet Visual Event (mentionné dans la réponse la plus populaire) ne vole que le cache du gestionnaire de bibliothèque personnalisé:

Il s'avère qu'il n'y a pas de méthode standard fournie par l'interface DOM recommandée par W3C pour savoir quels auditeurs d'événements sont attachés à un élément particulier. Bien que cela puisse sembler être un oubli, il y avait une proposition pour inclure une propriété appelée eventListenerList à la spécification DOM de niveau 3, mais a malheureusement été supprimée dans les versions ultérieures. En tant que tel, nous sommes forcés de regarder les bibliothèques Javascript individuelles, qui maintiennent généralement un cache d'événements attachés (afin qu'ils puissent ensuite être supprimés et effectuer d'autres abstractions utiles).

En tant que tel, pour que Visual Event affiche des événements, il doit pouvoir analyser les informations sur l'événement à partir d'une bibliothèque Javascript.

L'élimination des éléments peut être discutable (c'est-à-dire parce qu'il existe certaines fonctionnalités DOM spécifiques telles que les collections en direct, qui ne peuvent pas être codées dans JS), mais cela donne naissance à l'événementListenerList en mode natif et fonctionne dans Chrome, Firefox et Opera (ne fonctionne pas dans IE7 ).

Vous pouvez envelopper les méthodes DOM natives pour gérer les auditeurs d'événements en mettant ceci au sommet de votre <head> :

 <script> (function(w){ var originalAdd = w.addEventListener; w.addEventListener = function(){ // add your own stuff here to debug return originalAdd.apply(this, arguments); }; var originalRemove = w.removeEventListener; w.removeEventListener = function(){ // add your own stuff here to debug return originalRemove.apply(this, arguments); }; })(window); </script> 

H / T @ les2

Utilisez getEventListeners dans Google Chrome:

 getEventListeners(document.getElementByID('btnlogin')); getEventListeners($('#btnlogin')); 

Si vous avez Firebug , vous pouvez utiliser console.dir(object or array) pour imprimer un arbre agréable dans le journal de la console de n'importe quel scalaire, tableau ou objet JavaScript.

Essayer:

 console.dir(clickEvents); 

ou

 console.dir(window); 

Les outils de développement de Firefox le font maintenant. Les événements sont affichés en cliquant sur le bouton "ev" à droite de l'affichage de chaque élément, y compris les événements jQuery et DOM .

Capture d'écran du bouton de l'auditeur d'événements de Firefox Tools Developer dans l'onglet de l'inspecteur

Opera 12 (pas le dernier moteur Chrome Webkit basé) Dragonfly a eu pendant un certain temps et est évidemment affiché dans la structure DOM. À mon avis, c'est un débogueur supérieur et c'est la seule raison de rester pourquoi j'utilise toujours la version Opera 12 (il n'y a pas de version v13, v14 et la fonctionnalité de v15 Webkit manque encore de Dragonfly)

Entrez la description de l'image ici

Une solution entièrement fonctionnelle basée sur la réponse de Jan Turon – se comporte comme getEventListeners() partir de la console:

(Il y a un petit bogue avec des doublons. Il ne cesse pas beaucoup de toute façon.)

 (function() { Element.prototype._addEventListener = Element.prototype.addEventListener; Element.prototype.addEventListener = function(a,b,c) { if(c==undefined) c=false; this._addEventListener(a,b,c); if(!this.eventListenerList) this.eventListenerList = {}; if(!this.eventListenerList[a]) this.eventListenerList[a] = []; //this.removeEventListener(a,b,c); // TODO - handle duplicates.. this.eventListenerList[a].push({listener:b,useCapture:c}); }; Element.prototype.getEventListeners = function(a){ if(!this.eventListenerList) this.eventListenerList = {}; if(a==undefined) return this.eventListenerList; return this.eventListenerList[a]; }; Element.prototype.clearEventListeners = function(a){ if(!this.eventListenerList) this.eventListenerList = {}; if(a==undefined){ for(var x in (this.getEventListeners())) this.clearEventListeners(x); return; } var el = this.getEventListeners(a); if(el==undefined) return; for(var i = el.length - 1; i >= 0; --i) { var ev = el[i]; this.removeEventListener(a, ev.listener, ev.useCapture); } }; Element.prototype._removeEventListener = Element.prototype.removeEventListener; Element.prototype.removeEventListener = function(a,b,c) { if(c==undefined) c=false; this._removeEventListener(a,b,c); if(!this.eventListenerList) this.eventListenerList = {}; if(!this.eventListenerList[a]) this.eventListenerList[a] = []; // Find the event in the list for(var i=0;i<this.eventListenerList[a].length;i++){ if(this.eventListenerList[a][i].listener==b, this.eventListenerList[a][i].useCapture==c){ // Hmm.. this.eventListenerList[a].splice(i, 1); break; } } if(this.eventListenerList[a].length==0) delete this.eventListenerList[a]; }; })(); 

Usage:

someElement.getEventListeners([name]) – liste de retour des auditeurs d'événements, si le nom est défini return array of listeners for that event

someElement.clearEventListeners([name]) – supprime tous les auditeurs de l'événement, si le nom est défini, supprime seulement les auditeurs de cet événement

Prototype 1.7.1

 function get_element_registry(element) { var cache = Event.cache; if(element === window) return 0; if(typeof element._prototypeUID === 'undefined') { element._prototypeUID = Element.Storage.UID++; } var uid = element._prototypeUID; if(!cache[uid]) cache[uid] = {element: element}; return cache[uid]; } 

J'essaie de le faire dans jQuery 2.1 et avec la méthode " $().click() -> $(element).data("events").click; ", cela ne fonctionne pas.

Je me suis rendu compte que seules les fonctions $ ._ data () fonctionnent dans mon cas:

  $(document).ready(function(){ var node = $('body'); // Bind 3 events to body click node.click(function(e) { alert('hello'); }) .click(function(e) { alert('bye'); }) .click(fun_1); // Inspect the events of body var events = $._data(node[0], "events").click; var ev1 = events[0].handler // -> function(e) { alert('hello') var ev2 = events[1].handler // -> function(e) { alert('bye') var ev3 = events[2].handler // -> function fun_1() $('body') .append('<p> Event1 = ' + eval(ev1).toString() + '</p>') .append('<p> Event2 = ' + eval(ev2).toString() + '</p>') .append('<p> Event3 = ' + eval(ev3).toString() + '</p>'); }); function fun_1() { var txt = 'text del missatge'; alert(txt); } 
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <body> </body> 

Il existe une jolie extension de jQuery Events :

Entrez la description de l'image ici ( Source de sujet)