¿Cómo encontrar los oyentes de eventos en un nodo DOM en JavaScript o en depuración?
Tengo una página donde algunos escuchadores de eventos están asignados a cuadros de entrada y cuadros de selección. ¿Hay alguna manera de averiguar qué escuchadores de eventos están observando un nodo DOM en particular y para qué evento?
Los eventos se adjuntan usando:
- Prototype's
Event.observe;} addEventListenerdel DOM;- Como atributo de elemento
element.onclick.
Respuesta #1
Chrome, Vivaldi y Safari soportan getEventListeners(domElement) en la consola de sus Herramientas de Desarrollador.
Para la mayoría de los propósitos de depuración, esto podría usarse.
A continuación hay una muy buena referencia para usarlo:
función getEventListeners
Consejo muy votado de Clifford Fajardo de los comentarios:
getEventListeners($0) obtendrá los detectores de eventos para el elemento en el que te has enfocado en las herramientas de desarrollo de Chrome.
Respuesta #2
Si solo necesitas inspeccionar lo que está sucediendo en una página, podrías probar el bookmarklet Visual Event.
Actualización: Evento Visual 2 disponible.
Respuesta #3
Depende de cómo se adjunten los eventos. Para ilustrar, supongamos que tenemos el siguiente controlador de clic:
var handler = function() { alert('clicked!') };
Vamos a adjuntarlo a nuestro elemento usando diferentes métodos, algunos que permiten la inspección y otros que no.
Método A) manejador de evento único
element.onclick = handler;
// inspect
console.log(element.onclick); // "function() { alert('clicked!') }"
Método B) múltiples controladores de eventos
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étodo C): jQuery
$(element).click(handler);
1.3.x
// inspect var clickEvents = $(element).data("events").click; jQuery.each(clickEvents, function(key, value) { console.log(value) // "function() { alert('clicked!') }" })1.4.x (almacena el manejador dentro de un objeto)
// inspect var clickEvents = $(element).data("events").click; jQuery.each(clickEvents, function(key, handlerObj) { console.log(handlerObj.handler) // "function() { alert('clicked!') }" // also available: handlerObj.type, handlerObj.namespace })1.7+ (muy bien)
Hecho usando el conocimiento de este comentario.
events = $._data(this, 'events'); for (type in events) { events[type].forEach(function (event) { console.log(event['handler']); }); }
(Ver jQuery.fn.data y jQuery.data)
Método D): Prototipo (desordenado)
$(element).observe('click', handler);
1.5.x
// inspect Event.observers.each(function(item) { if(item[0] == element) { console.log(item[2]) // "function() { alert('clicked!') }" } })1.6 a 1.6.0.3, inclusive (aquí se volvió muy difícil)
// 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){ console.log(wrapper.handler) // "function() { alert('clicked!') }" })1.6.1 (un poco mejor)
// inspect var clickEvents = element.getStorage().get('prototype_event_registry').get('click'); clickEvents.each(function(wrapper){ console.log(wrapper.handler) // "function() { alert('clicked!') }" })
Al hacer clic en la salida resultante en la consola (que muestra el texto de la función), la consola navegará directamente a la línea de la declaración de la función en el archivo JS correspondiente.
Respuesta #4
El inspector WebKit en los navegadores Chrome o Safari ahora hace esto. Mostrará los oyentes de eventos para un elemento DOM cuando lo selecciones en el panel de Elementos.
Respuesta #5
Es posible listar todos los escuchadores de eventos en JavaScript: No es tan difícil; solo tienes que hackear el método del prototype de los elementos HTML (antes de agregar los escuchadores).
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});
};
Ahora cada elemento de ancla (a) tendrá una propiedad lastListenerInfo que contiene todos sus listeners. Y incluso funciona para eliminar listeners con funciones anónimas.
Respuesta #6
Usa getEventListeners en Google Chrome:
getEventListeners(document.getElementByID('btnlogin'));
getEventListeners($('#btnlogin'));
Respuesta #7
(Reescribiendo la respuesta de esta pregunta ya que es relevante aquí.)
Al depurar, si solo quieres ver los eventos, recomiendo ya sea...
- Evento visual
- La sección Elements de las Herramientas de Desarrollador de Chrome: selecciona un elemento y busca "Event Listeners" en la parte inferior derecha (similar en Firefox)
Si quieres usar los eventos en tu código, y estás usando jQuery antes de la versión 1.8, puedes usar:
$(selector).data("events")
para obtener los eventos. A partir de la versión 1.8, el uso de .data("events") está descontinuado (ver este ticket de error). Puedes usar:
$._data(element, "events")
Otro ejemplo: Escribe todos los eventos de clic en un cierto enlace en la consola:
var $myLink = $('a.myClass');
console.log($._data($myLink[0], "events").click);
(ver http://jsfiddle.net/HmsQC/ para un ejemplo funcional)
Desafortunadamente, usar $._data no se recomienda excepto para depuración, ya que es una estructura interna de jQuery y podría cambiar en futuras versiones. Desafortunadamente, no conozco otro medio fácil de acceder a los eventos.
Respuesta #8
1: Prototype.observe utiliza Element.addEventListener (ver el código fuente)
2: Puedes sobrescribir Element.addEventListener para recordar los listeners añadidos (la práctica propiedad EventListenerList fue eliminada de la propuesta de la especificación DOM3). Ejecuta este código antes de que se adjunte cualquier evento:
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);
};
Leer todos los eventos por:
var clicks = someElement.eventListenerList.click;
if(clicks) clicks.forEach(function(f) {
alert("I listen to this function: "+f.toString());
});
Y no olvides sobrescribir Element.removeEventListener para eliminar el evento de la Element.eventListenerList personalizada.
3: la propiedad Element.onclick necesita un cuidado especial aquí:
if(someElement.onclick)
alert("I also listen tho this: "+someElement.onclick.toString());
4: no olvides el atributo de contenido Element.onclick: estas son dos cosas diferentes:
someElement.onclick = someHandler; // IDL attribute
someElement.setAttribute("onclick","otherHandler(event)"); // content attribute
Así que tú también necesitas manejarlo:
var click = someElement.getAttribute("onclick");
if(click) alert("I even listen to this: "+click);
El bookmarklet Visual Event (mencionado en la respuesta más popular) solo roba la caché del manejador de la biblioteca personalizada:
Resulta que no existe un método estándar proporcionado por la interfaz DOM recomendada por el W3C para averiguar qué detectores de eventos están adjuntos a un elemento en particular. Aunque esto podría parecer una omisión, hubo una propuesta para incluir una propiedad llamada eventListenerList en la especificación DOM de nivel 3, pero desafortunadamente fue eliminada en borradores posteriores. Como tal, nos vemos obligados a examinar las bibliotecas individuales de Javascript, que típicamente mantienen una caché de los eventos adjuntos (para que puedan ser eliminados más tarde y realizar otras abstracciones útiles).
Como tal, para que Visual Event pueda mostrar eventos, debe ser capaz de analizar la información del evento de una biblioteca de Javascript.
La sobrescritura de elementos puede ser cuestionable (es decir, porque hay algunas características específicas del DOM como las colecciones en vivo, que no se pueden codificar en JS), pero proporciona soporte nativo para eventListenerList y funciona en Chrome, Firefox y Opera (no funciona en IE7).
Respuesta #9
Pega en la consola para obtener todos los eventListeners impresos junto a su elemento HTML
Array.from(document.querySelectorAll("*")).forEach(element => {
const events = getEventListeners(element)
if (Object.keys(events).length !== 0) {
console.log(element, events)
}
})
Respuesta #10
Podrías envolver los métodos nativos del DOM para administrar los listeners de eventos colocando esto en la parte superior de tu <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>
Créditos a @les2
Respuesta #11
Las herramientas de desarrollo de Firefox ahora hacen esto. Los eventos se muestran al hacer clic en el botón "ev" a la derecha de la visualización de cada elemento, incluidos los eventos de jQuery y del DOM.
Respuesta #12
Actualización 2022:
En las Herramientas de desarrollo de Chrome, en el panel de Elementos, hay una pestaña de Listeners de eventos, donde puedes ver los listeners del elemento.
También puedes desmarcar "Ancestors" para que solo muestre los oyentes de ese elemento
Respuesta #13
Si tienes Firebug, puedes usar console.dir(object o array) para imprimir un bonito árbol en el registro de la consola de cualquier escalar, array u objeto de JavaScript.
Intenta :
console.dir(clickEvents);
o
console.dir(window);
Respuesta #14
Solución completamente funcional basada en la respuesta de Jan Turon - se comporta como getEventListeners() de la consola:
(Hay un pequeño error con los duplicados. De todos modos, no causa mucho problema.)
(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];
};
})();
Uso :
someElement.getEventListeners([name]) - devuelve una lista de escuchadores de eventos; si se establece name, devuelve un array de escuchadores para ese evento
someElement.clearEventListeners([name]) - elimina todos los escuchadores de eventos, si se establece name solo elimina los escuchadores de ese evento
Respuesta #15
Opera 12 (no basada en el último motor Webkit de Chrome) Dragonfly ha tenido esto por un tiempo y obviamente se muestra en la estructura DOM. En mi opinión, es un depurador superior y es la única razón por la que todavía uso la versión basada en Opera 12 (no hay una versión v13, v14 y la v15 basada en Webkit todavía carece de Dragonfly)


