web-dev-qa-db-fra.com

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

J'ai une page où des écouteurs d'événements sont attachés à des zones de saisie et à des zones de sélection. Existe-t-il un moyen de savoir quels écouteurs d'événements observent un nœud DOM particulier et pour quel événement?

Les événements sont attachés en utilisant:

  1. Prototype'sEvent.observe;
  2. addEventListener de DOM;
  3. En tant qu'attribut d'élément element.onclick.
739
Navneet

Si vous devez simplement inspecter ce qui se passe sur une page, vous pouvez essayer le Visual Event bookmarklet.

Update: Visual Event 2 disponible;

485
Andrew Hedges

Cela dépend de la façon dont les événements sont liés. Pour illustration, nous avons le gestionnaire de clics suivant:

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

Nous allons l'attacher à notre élément en utilisant différentes méthodes, certaines permettant l'inspection et d'autres non.

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

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

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

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 (en désordre)

$(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, inclus (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!') }"
    })
    
352
Crescent Fresh

Chrome, Firefox, Vivaldi et Safari prennent en charge getEventListeners(domElement) dans leur console des outils de développement.

Cela pourrait être utilisé pour la majorité des tâches de débogage. 

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

233
Raghav

WebKit Inspector dans les navigateurs Chrome ou Safari fait maintenant ceci. Les écouteurs d'événements d'un élément DOM s'afficheront lorsque vous le sélectionnerez dans le volet Éléments.

85
Ishan

Il est possible de lister tous les écouteurs d'événements en JavaScript: Ce n'est pas si difficile; il suffit de pirater la méthode prototype des éléments HTML (avant ajoutant les écouteurs).

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});
};

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

65
Ivan Castellanos

(Réécriture de la réponse de cette question car elle est pertinente ici.)

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

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

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

$(selector).data("events")

pour obtenir les événements. Depuis la version 1.8, l'utilisation de .data ("events") est abandonnée (voir ce ticket de bogue ). Vous pouvez utiliser:

$._data(element, "events")

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, using $ ._ data, cela n’est pas recommandé sauf pour le débogage car il s’agit d’une structure interne jQuery et pourrait changer dans les prochaines versions. Malheureusement, je ne connais aucun autre moyen facile d'accéder aux événements.

40
Luke

Utilisez getEventListeners dans Google Chrome :

getEventListeners(document.getElementByID('btnlogin'));
getEventListeners($('#btnlogin'));
38
Pranay Soni

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

2: Vous pouvez remplacer Element.addEventListener pour mémoriser les écouteurs ajoutés (la propriété pratique EventListenerList a été supprimée de la proposition de spécification DOM3). Exécutez ce code avant qu'aucun événement ne soit attaché:

(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);
  };
})();

Lire tous les événements de:

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 du Element.eventListenerList personnalisé.

3: la propriété Element.onclick nécessite des soins particuliers ici:

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

4: n'oubliez pas l'attribut Element.onclick content: ce sont deux choses différentes:

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

Donc, vous devez aussi vous en occuper:

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 courante) ne vole que le cache du gestionnaire de bibliothèque personnalisé:

Il s’avère qu’aucune méthode standard n’est fournie par le W3C interface DOM recommandée pour savoir ce que sont les écouteurs d'événement attaché à un élément particulier. Bien que cela puisse sembler être un surveillance, il y avait une proposition d'inclure une propriété appelée eventListenerList selon la spécification DOM de niveau 3, mais était malheureusement été supprimé dans les versions ultérieures. En tant que tels, nous sommes obligés de regardé les bibliothèques Javascript individuelles, qui typiquement conservez une mémoire cache des événements attachés (afin qu'ils puissent être supprimés plus tard et effectuer d'autres abstractions utiles).

En tant que tel, pour que Visual Event puisse afficher les événements, il doit être capable de analyser les informations sur l'événement à partir d'une bibliothèque Javascript.

Remplacer les éléments peut être discutable (c’est-à-dire qu’il existe certaines fonctionnalités propres à DOM, telles que les collections actives, qui ne peuvent pas être codées en JS), mais cela donne le support natif à eventListenerList et fonctionne dans Chrome, Firefox et Opera (ne fonctionne pas dans IE7). ).

25
Jan Turoň

Vous pouvez envelopper les méthodes du DOM natif pour la gestion des écouteurs d'événements en plaçant ceci en haut 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

21
Jon z

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 jQuery et DOM .

Screenshot of Firefox developer tools' event listener button in the inspector tab

18
simonzack

Si vous avez Firebug , vous pouvez utiliser console.dir(object or array) pour imprimer une jolie arborescence dans le journal de la console de tout scalaire, tableau ou objet JavaScript. 

Essayer: 

console.dir(clickEvents);

ou

console.dir(window);
12
Michael Butler

Solution totalement opérationnelle basée sur réponse de Jan Turon - se comporte comme getEventListeners() à partir de la console:

(Il y a un petit bug avec les doublons. De toute façon, ça ne casse pas beaucoup.)

(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]) - renvoie la liste des écouteurs d'événement, si name est défini, retourne un tableau d'écouteurs pour cet événement

someElement.clearEventListeners([name]) - supprime tous les écouteurs d'événement, si name est défini, supprime uniquement les écouteurs pour cet événement

7
n00b

Opera 12 (pas le dernier moteur Chrome Webkit basé) Dragonfly a cela depuis un moment et est évidemment affiché dans la structure DOM. A mon avis, c'est un débogueur supérieur et c'est la seule raison pour laquelle j'utilise toujours la version basée sur Opera 12 (il n'y a pas de version v13, v14 et la version v15 de Webkit manque toujours de Dragonfly)

enter image description here

7
Daniel Sokolowski

Manière 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];
}
4
Ronald

Il existe Nice extension jQuery Events:

 enter image description here (sujet source )

3
T.Todua

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

J'ai réalisé que seules les fonctions $ ._ data () fonctionnaient 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>

2
Joel Barba

changer ces fonctions vous permettra de connecter les écouteurs ajoutés:

EventTarget.prototype.addEventListener
EventTarget.prototype.attachEvent
EventTarget.prototype.removeEventListener
EventTarget.prototype.detachEvent

lire le reste des auditeurs avec

console.log(someElement.onclick);
console.log(someElement.getAttribute("onclick"));
0
Aiden Waterman

Je travaillais récemment avec des événements et je voulais voir/contrôler tous les événements d'une page. Après avoir examiné les solutions possibles, j'ai décidé de suivre mon propre chemin et de créer un système personnalisé pour surveiller les événements. Donc, j'ai fait trois choses.

Premièrement, j'avais besoin d'un conteneur pour tous les écouteurs d'événement de la page: c'est l'objet EventListeners. Il existe trois méthodes utiles: add(), remove() et get().

Ensuite, j'ai créé un objet EventListener pour contenir les informations nécessaires à l'événement, c'est-à-dire: target, type, callback, options, useCapture, wantsUntrusted et j'ai ajouté une méthode remove() pour supprimer l'auditeur.

Enfin, j'ai étendu les méthodes natives addEventListener() et removeEventListener() pour les faire fonctionner avec les objets que j'ai créés (EventListener et EventListeners).

Usage:

var bodyClickEvent = document.body.addEventListener("click", function () {
    console.log("body click");
});

// bodyClickEvent.remove();

addEventListener() crée un objet EventListener, l'ajoute à EventListeners et renvoie l'objet EventListener pour qu'il puisse être supprimé ultérieurement.

EventListeners.get() peut être utilisé pour afficher les écouteurs dans la page. Il accepte un EventTarget ou une chaîne (type d'événement).

// EventListeners.get(document.body);
// EventListeners.get("click");

Démo

Disons que nous voulons connaître tous les écouteurs d'événements de cette page. Nous pouvons le faire (en supposant que vous utilisez une extension de gestionnaire de script, Tampermonkey dans ce cas). Le script suivant fait ceci:

// ==UserScript==
// @name         New Userscript
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  try to take over the world!
// @author       You
// @include      https://stackoverflow.com/*
// @grant        none
// ==/UserScript==

(function() {
    fetch("https://raw.githubusercontent.com/akinuri/js-lib/master/EventListener.js")
        .then(function (response) {
            return response.text();
        })
        .then(function (text) {
            eval(text);
            window.EventListeners = EventListeners;
        });
})(window);

Et quand nous listons tous les auditeurs, cela signifie qu'il y a 299 auditeurs d'événements. Il semble y avoir des doublons, mais je ne sais pas s'ils sont vraiment des doublons. Tous les types d'événements ne sont pas dupliqués. Tous ces "doublons" peuvent donc être un auditeur individuel.

 screenshot of console listing all event listeners in this page

Le code peut être trouvé sur mon référentiel. Je ne voulais pas le poster ici parce que c'est plutôt long.


Update: Cela ne semble pas fonctionner avec jQuery. Lorsque j'examine EventListener, je vois que le rappel est

function(b){return"undefined"!=typeof r&&r.event.triggered!==b.type?r.event.dispatch.apply(a,arguments):void 0}

Je crois que cela appartient à jQuery et n'est pas le rappel réel. jQuery stocke le rappel actuel dans les propriétés de EventTarget:

$(document.body).click(function () {
    console.log("jquery click");
});

 enter image description here

Pour supprimer un écouteur d'événement, le rappel réel doit être transmis à la méthode removeEventListener(). Donc, pour que cela fonctionne avec jQuery, il doit encore être modifié. Je pourrais résoudre ce problème à l'avenir.

0
akinuri