it-swarm.com.de

Wie finden Sie Ereignis-Listener auf einem DOM-Knoten beim Debuggen oder aus dem JavaScript-Code?

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:

  1. PrototypesEvent.observe;
  2. DOMs addEventListener;
  3. Als Elementattribut element.onclick.
739
Navneet

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;

485
Andrew Hedges

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

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

233
Raghav

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.

85
Ishan

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.

65

(Umschreiben der Antwort von dieser Frage da sie hier relevant ist.)

Wenn Sie beim Debuggen nur die Ereignisse sehen möchten, empfehle ich entweder ... 

  1. Visuelles Ereignis
  2. Der Abschnitt Elements der Chrome-Entwicklertools: Wählen Sie ein Element aus und suchen Sie unten rechts nach "Event Listeners" (ähnlich wie in Firefox).

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.

40
Luke

Verwenden Sie getEventListeners in Google Chrome :

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

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 ).

25
Jan Turoň

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

21
Jon z

Die Firefox-Entwicklertools tun dies jetzt. Ereignisse werden durch Klicken auf die Schaltfläche "ev" rechts von der Anzeige jedes Elements angezeigt, einschließlich jQuery und DOM events.

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

18
simonzack

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);
12
Michael Butler

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

7
n00b

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).

enter image description here

7

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

Es gibt eine Nice jQuery Events Erweiterung:

 enter image description here (thema source )

3
T.Todua

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>

2
Joel Barba

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.

screenshot of console listing all event listeners in this page

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

enter image description here

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.

1
akinuri

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"));
0
Aiden Waterman