Ich habe eine Seite, auf der einige Ereignis-Listener Eingabefeldern und Auswahlfeldern zugeordnet sind. Gibt es eine Möglichkeit herauszufinden, welche Ereignis-Listener einen bestimmten DOM-Knoten beobachten und für welches Ereignis?
Ereignisse werden angehängt mit:
Event.observe
;addEventListener
;element.onclick
.Wenn Sie nur prüfen müssen, was auf einer Seite passiert, können Sie das Visual Event Bookmarklet verwenden.
Update: Visuelles Ereignis 2 verfügbar;
Es hängt davon ab, wie die Ereignisse verbunden sind. Zur Veranschaulichung haben wir den folgenden Click-Handler:
var handler = function() { alert('clicked!') };
Wir werden es mit verschiedenen Methoden an unser Element anhängen. Einige erlauben Inspektionen, andere nicht.
Methode A) Einzelner Eventhandler
element.onclick = handler;
// inspect
alert(element.onclick); // alerts "function() { alert('clicked!') }"
Methode B) mehrere Event-Handler
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
Methode 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 (speichert den Handler in einem Objekt)
// 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
})
(Siehe jQuery.fn.data
und jQuery.data
)
Methode D): Prototyp (unordentlich)
$(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 bis 1.6.0.3, inklusive (wurde hier sehr schwierig)
// 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 (etwas besser)
// 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 und Safari unterstützen getEventListeners(domElement)
in ihrer Developer Tools-Konsole.
Für die Mehrzahl der Debugging-Zwecke kann dies verwendet werden.
Im Folgenden finden Sie eine sehr gute Referenz, um sie zu verwenden: https://developers.google.com/chrome-developer-tools/docs/commandline-api#geteventlistenersobject
WebKit Inspector in Chrome- oder Safari-Browsern macht dies jetzt. Die Ereignis-Listener für ein DOM-Element werden angezeigt, wenn Sie es im Elementbereich auswählen.
Es ist möglich, alle Ereignis-Listener aufzulisten in JavaScript: Es ist nicht so schwer; Sie müssen nur die prototype
-Methode der HTML-Elemente hacken (before, die die Listener hinzufügt).
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});
};
Nun hat jedes Ankerelement (a
) eine lastListenerInfo
-Eigenschaft, die alle seine Listener enthält. Und es funktioniert sogar, um Listener mit anonymen Funktionen zu entfernen.
(Umschreiben der Antwort von dieser Frage da sie hier relevant ist.)
Wenn Sie beim Debuggen nur die Ereignisse sehen möchten, empfehle ich entweder ...
Wenn Sie die Ereignisse in Ihrem Code verwenden möchten und jQuery vor Version 1.8 verwenden, können Sie Folgendes verwenden:
$(selector).data("events")
um die Ereignisse zu erhalten. Ab Version 1.8 wird die Verwendung von .data ("events") eingestellt) (siehe dieses Bugticket ). Sie können verwenden:
$._data(element, "events")
Ein anderes Beispiel: Schreiben Sie alle Klickereignisse auf einen bestimmten Link in die Konsole:
var $myLink = $('a.myClass');
console.log($._data($myLink[0], "events").click);
(siehe http://jsfiddle.net/HmsQC/ für ein Arbeitsbeispiel)
Leider ist mit $ ._ data wird dies nicht empfohlen außer zum Debuggen, da es sich um eine interne jQuery-Struktur handelt, die sich in zukünftigen Versionen ändern kann. Ich kenne leider keine andere einfache Möglichkeit, um auf die Ereignisse zuzugreifen.
Verwenden Sie getEventListeners in Google Chrome :
getEventListeners(document.getElementByID('btnlogin'));
getEventListeners($('#btnlogin'));
1: Prototype.observe
verwendet Element.addEventListener (siehe den Quellcode )
2: Sie können Element.addEventListener
überschreiben, um sich die hinzugefügten Listener zu merken (die praktische Eigenschaft EventListenerList
wurde aus dem DOM3-Spezifikationsvorschlag entfernt). Führen Sie diesen Code aus, bevor ein Ereignis angehängt wird:
(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);
};
})();
Lesen Sie alle Veranstaltungen von:
var clicks = someElement.eventListenerList.click;
if(clicks) clicks.forEach(function(f) {
alert("I listen to this function: "+f.toString());
});
Vergessen Sie nicht, Element.removeEventListener
zu überschreiben, um das Ereignis aus dem benutzerdefinierten Element.eventListenerList
zu entfernen.
3: Die Element.onclick
-Eigenschaft muss hier besonders sorgfältig behandelt werden:
if(someElement.onclick)
alert("I also listen tho this: "+someElement.onclick.toString());
4: Vergessen Sie nicht das Inhaltsattribut Element.onclick
: Dies sind zwei verschiedene Dinge:
someElement.onclick = someHandler; // IDL attribute
someElement.setAttribute("onclick","otherHandler(event)"); // content attribute
Also musst du auch damit umgehen:
var click = someElement.getAttribute("onclick");
if(click) alert("I even listen to this: "+click);
Das Visual Event-Bookmarklet (in der beliebtesten Antwort erwähnt) stiehlt nur den Cache für benutzerdefinierte Bibliothekshandler:
Es stellt sich heraus, dass vom W3C keine Standardmethode zur Verfügung gestellt wird empfohlene DOM-Schnittstelle, um herauszufinden, welche Ereignislistener sind an einem bestimmten Element befestigt. Dies scheint zwar ein Versehen gab es einen Vorschlag, eine Eigenschaft namens .__ aufzunehmen. eventListenerList zur DOM-Spezifikation der Ebene 3, war jedoch wurde in späteren Entwürfen leider entfernt. Als solche sind wir gezwungen, schaute auf die einzelnen Javascript-Bibliotheken, die normalerweise einen Cache mit angehängten Ereignissen verwalten (damit sie später entfernt werden können und andere nützliche Abstraktionen ausführen).
Damit Visual Event Ereignisse anzeigen kann, muss es in der Lage sein, Analysieren Sie die Ereignisinformationen aus einer Javascript-Bibliothek.
Das Überschreiben von Elementen kann fragwürdig sein (z. B. weil es einige DOM-spezifische Features gibt, wie z. B. Live-Sammlungen, die in JS nicht codiert werden können), es gibt jedoch die native Unterstützung für eventListenerList und funktioniert in Chrome, Firefox und Opera (funktioniert nicht in IE7 ).
Sie können die systemeigenen DOM-Methoden für die Verwaltung von Ereignis-Listenern einschließen, indem Sie dies oben in <head>
einfügen:
<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
Wenn Sie Firebug haben, können Sie console.dir(object or array)
verwenden, um einen Nizza-Baum im Konsolenprotokoll eines beliebigen JavaScript-Skalars, Arrays oder Objekts zu drucken.
Versuchen:
console.dir(clickEvents);
oder
console.dir(window);
Voll funktionsfähige Lösung basierend auf answer von Jan Turon - verhält sich wie getEventListeners()
von der Konsole aus:
(Es gibt ein kleines Problem mit Duplikaten. Es bricht sowieso nicht viel.)
(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];
};
})();
Verwendungszweck:
someElement.getEventListeners([name])
- Gibt die Liste der Ereignis-Listener zurück, wenn name für das Ereignis festgelegt ist
someElement.clearEventListeners([name])
- Entfernt alle Ereignis-Listener, wenn Name festgelegt ist, werden nur Listener für dieses Ereignis entfernt
Opera 12 (nicht die neueste auf Chrome Webkit basierende Engine) Dragonfly hat dies für eine Weile und wird offensichtlich in der DOM-Struktur angezeigt. Meiner Meinung nach ist es ein überlegener Debugger und der einzige Grund, warum ich immer noch die auf Opera 12 basierende Version verwende (es gibt keine Version von v13, v14 und dem auf v15 basierenden Webkit fehlt Dragonfly noch).
Weg des Prototyps 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];
}
Es gibt eine Nice jQuery Events Erweiterung:
(thema source )
Ich versuche das in jQuery 2.1 zu tun und mit der "$().click() -> $(element).data("events").click;
" -Methode funktioniert es nicht.
Mir wurde klar, dass in meinem Fall nur die $ ._ data () - Funktion funktioniert:
$(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>
Ich habe kürzlich mit Ereignissen gearbeitet und wollte alle Ereignisse auf einer Seite anzeigen/steuern. Nachdem ich nach möglichen Lösungen gesucht hatte, beschloss ich, meinen eigenen Weg zu gehen und ein benutzerdefiniertes System zur Überwachung von Ereignissen zu erstellen. Also habe ich drei Dinge getan.
Zuerst brauchte ich einen Container für alle Ereignis-Listener auf der Seite: Das ist das Objekt EventListeners
. Es gibt drei nützliche Methoden: add()
, remove()
und get()
.
Als Nächstes habe ich ein EventListener
-Objekt erstellt, um die erforderlichen Informationen für das Ereignis zu speichern: target
, type
, callback
, options
, useCapture
, wantsUntrusted
und fügte eine Methode remove()
hinzu, um den Listener zu entfernen.
Zuletzt habe ich die systemeigenen Methoden addEventListener()
und removeEventListener()
erweitert, damit sie mit den von mir erstellten Objekten (EventListener
und EventListeners
) funktionieren.
Verwendungszweck:
var bodyClickEvent = document.body.addEventListener("click", function () {
console.log("body click");
});
// bodyClickEvent.remove();
addEventListener()
erstellt ein EventListener
Objekt, fügt es zu EventListeners
hinzu und gibt das EventListener
Objekt zurück, damit es später entfernt werden kann.
EventListeners.get()
kann verwendet werden, um die Listener auf der Seite anzuzeigen. Es akzeptiert ein EventTarget
oder eine Zeichenfolge (Ereignistyp).
// EventListeners.get(document.body);
// EventListeners.get("click");
Demo
Angenommen, wir möchten jeden Ereignis-Listener auf dieser aktuellen Seite kennenlernen. Wir können das tun (vorausgesetzt, Sie verwenden eine Skriptmanager-Erweiterung, in diesem Fall Tampermonkey). Folgendes Skript macht das:
// ==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);
Und wenn wir alle Listener auflisten, heißt es, dass es 299 Event-Listener gibt. Es "scheint" einige Duplikate zu geben, aber ich weiß nicht, ob es sich wirklich um Duplikate handelt. Da nicht jeder Ereignistyp dupliziert wird, können alle diese "Duplikate" ein einzelner Listener sein.
Code kann in meinem Repository gefunden werden. Ich wollte ihn hier nicht posten, weil er ziemlich lang ist.
Update: Dies scheint mit jQuery nicht zu funktionieren. Wenn ich den EventListener untersuche, sehe ich, dass der Rückruf ist
function(b){return"undefined"!=typeof r&&r.event.triggered!==b.type?r.event.dispatch.apply(a,arguments):void 0}
Ich glaube, das gehört zu jQuery und ist nicht der eigentliche Rückruf. jQuery speichert den tatsächlichen Rückruf in den Eigenschaften des EventTarget:
$(document.body).click(function () {
console.log("jquery click");
});
Um einen Ereignis-Listener zu entfernen, muss der tatsächliche Rückruf an die Methode removeEventListener()
übergeben werden. Damit dies mit jQuery funktioniert, müssen weitere Änderungen vorgenommen werden. Ich könnte das in Zukunft beheben.
wenn Sie diese Funktionen ändern, können Sie die hinzugefügten Listener protokollieren:
EventTarget.prototype.addEventListener
EventTarget.prototype.attachEvent
EventTarget.prototype.removeEventListener
EventTarget.prototype.detachEvent
lesen Sie den Rest der Zuhörer mit
console.log(someElement.onclick);
console.log(someElement.getAttribute("onclick"));