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:
Event.observe
;addEventListener
de DOM;element.onclick
.Si vous devez simplement inspecter ce qui se passe sur une page, vous pouvez essayer le Visual Event bookmarklet.
Update: Visual Event 2 disponible;
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!') }"
})
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
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.
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.
(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 ...
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.
Utilisez getEventListeners dans Google Chrome :
getEventListeners(document.getElementByID('btnlogin'));
getEventListeners($('#btnlogin'));
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). ).
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
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);
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
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)
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];
}
Il existe Nice extension jQuery Events:
(sujet source )
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>
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"));
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.
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");
});
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.