Jak znaleźć detektory zdarzeń na węźle DOM podczas debugowania lub z kodu JavaScript?

Mam stronę, na której niektóre słuchacze zdarzeń są dołączone do pól wprowadzania i wyboru. Czy istnieje sposób, aby dowiedzieć się, które zdarzenia słuchacze obserwują dany węzeł DOM i dla jakiego zdarzenia?

Zdarzenia są dołączane za pomocą:

  1. Prototype ' s Event.observe;
  2. DOM ' s addEventListener;
  3. jako atrybut elementu element.onclick.
Author: Peter Mortensen, 2009-01-15

17 answers

Jeśli chcesz sprawdzić, co dzieje się na stronie, możesz wypróbować bookmarklet Event wizualny.

Aktualizacja: Event wizualny 2 Dostępny;

 469
Author: Andrew Hedges,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-10 08:52:35

To zależy od tego, jak wydarzenia są dołączone. Dla ilustracji Załóżmy, że mamy następujący handler kliknięć:

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

Będziemy dołączać go do naszego elementu za pomocą różnych metod, niektóre, które pozwalają na inspekcję, a inne, które nie.

Metoda a) obsługa pojedynczego zdarzenia

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

Metoda B) obsługa wielu zdarzeń

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

Metoda 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 (przechowuje handler wewnątrz obiekt)

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

(Zobacz też jQuery.fn.data oraz jQuery.data)

Metoda D): Prototype (13)

$(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 do 1.6.0.3, włącznie (tutaj bardzo trudno)

    // 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 (trochę lepiej)

    // inspect
    var clickEvents = element.getStorage().get('prototype_event_registry').get('click');
    clickEvents.each(function(wrapper){
        alert(wrapper.handler) // alerts "function() { alert('clicked!') }"
    })
    
 346
Author: Crescent Fresh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-03-04 15:50:45

Chrome, Firefox, Vivaldi i Safari wspierają getEventListeners(domElement) w konsoli narzędzi programistycznych.

Dla większości celów debugowania można to wykorzystać.

Poniżej jest bardzo dobre odniesienie do korzystania z niego: https://developers.google.com/chrome-developer-tools/docs/commandline-api#geteventlistenersobject

 214
Author: Raghav,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-05 19:33:41

WebKit Inspector w przeglądarkach Chrome lub Safari teraz to robi. Po zaznaczeniu elementu w panelu Elements wyświetlane będą detektory zdarzeń dla elementu DOM.

 82
Author: Ishan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-01-17 07:39:55

Możliwe jest wyświetlenie wszystkich detektorów zdarzeń w JavaScript: nie jest to takie trudne; wystarczy zhakować metodę prototype elementów HTML (przed dodaniem detektorów).

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

Teraz każdy element anchor (a) będzie miał właściwość lastListenerInfo, która zawiera wszystkie jego słuchacze. A nawet działa do usuwania słuchaczy z anonimowymi funkcjami.

 62
Author: Ivan Castellanos,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-07-30 00:11:42

(przepisanie odpowiedzi z tego pytania ponieważ jest to istotne tutaj.)

Podczas debugowania, jeśli chcesz tylko zobaczyć zdarzenia, polecam albo...

  1. Event Wizualny
  2. W przeglądarce Firefox można wybrać opcję "Event Listeners", a następnie wybrać opcję "Event Listeners" w prawym dolnym rogu (podobnie w przeglądarce Firefox).]}

Jeśli chcesz użyć zdarzeń w kodzie, a używasz jQuery przed wersją 1.8 , można użyć:

$(selector).data("events")

Aby uzyskać wydarzenia. od wersji 1.8, za pomocą .dane ("zdarzenia") zostały przerwane (zobacz ten zgłoszenie błędu). Można użyć:

$._data(element, "events")

Inny przykład: zapisz wszystkie zdarzenia kliknięcia na określonym linku do konsoli:

var $myLink = $('a.myClass');
console.log($._data($myLink[0], "events").click);

(patrz http://jsfiddle.net/HmsQC/ dla przykładu roboczego)

Niestety, używając $._data nie jest to zalecane z wyjątkiem debugowania, ponieważ jest to wewnętrzna struktura jQuery i może ulec zmianie w przyszłych wydaniach. Niestety nie znam innych łatwych sposobów dostępu do wydarzeń.

 38
Author: Luke,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:47:29

Użyj getEventListeners w Google Chrome :

getEventListeners(document.getElementByID('btnlogin'));
getEventListeners($('#btnlogin'));
 29
Author: Pranay Soni,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-03 23:32:26

1: Prototype.observe używa elementu.addEventListener (patrz kod źródłowy )

2: możesz nadpisać Element.addEventListener, Aby zapamiętać dodane słuchacze (handy właściwość EventListenerList została usunięta z dom3 Spec proposal). Uruchom ten kod przed dołączeniem jakiegokolwiek zdarzenia:

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

Przeczytaj wszystkie wydarzenia według:

var clicks = someElement.eventListenerList.click;
if(clicks) clicks.forEach(function(f) {
  alert("I listen to this function: "+f.toString());
});

I nie zapomnij nadpisać Element.removeEventListener, aby usunąć zdarzenie z niestandardowego Element.eventListenerList.

3: Element.onclick nieruchomość wymaga szczególnej opieki tutaj:

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

4: nie zapomnij o Element.onclick atrybut treści: są to dwie różne rzeczy:

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

Więc ty też musisz się tym zająć:

var click = someElement.getAttribute("onclick");
if(click) alert("I even listen to this: "+click);

Visual event bookmarklet (wspomniany w najpopularniejszej odpowiedzi) kradnie tylko niestandardową pamięć podręczną obsługi biblioteki:

Okazuje się, że nie ma standardowej metody zapewnionej przez W3C zalecany interfejs DOM, aby dowiedzieć się, czym są słuchacze zdarzeń dołączony do określonego elementu. Chociaż może się to wydawać Nadzór, była propozycja aby uwzględnić nieruchomość o nazwie eventListenerList do specyfikacji Dom poziomu 3, ale był niestety został usunięty w późniejszych projektach. Jako takie jesteśmy zmuszeni do przyjrzał się poszczególnym bibliotekom Javascript, które zazwyczaj zachowaj pamięć podręczną dołączonych zdarzeń (aby można je później usunąć i wykonywanie innych użytecznych abstrakcji).

Jako takie, aby Zdarzenie wizualne pokazywało zdarzenia, musi być w stanie analizuje informacje o zdarzeniu z Javascript biblioteka.

Nadpisywanie elementów może być wątpliwe (np. ponieważ istnieją pewne specyficzne dla DOM funkcje, takie jak live collections, które nie mogą być kodowane w JS), ale daje natywne wsparcie dla eventListenerList i działa w Chrome, Firefox i Opera (nie działa w IE7).

 23
Author: Jan Turoň,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-06-27 10:05:40

Możesz zawinąć natywne metody DOM do zarządzania słuchaczami zdarzeń, umieszczając je na górze <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
Author: Jon z,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-11-06 17:49:11

Narzędzia programistyczne Firefoksa teraz to robią. Zdarzenia są wyświetlane poprzez kliknięcie przycisku " ev " po prawej stronie każdego elementu, w tym zdarzeń jQuery i DOM.

Zrzut ekranu przycisku słuchacza zdarzeń Firefox developer tools na karcie Inspektor

 17
Author: simonzack,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-29 17:43:30

Jeśli masz Firebug, możesz użyć console.dir(object or array), aby wydrukować ładne drzewo w dzienniku konsoli dowolnego skalaru, tablicy lub obiektu JavaScript.

Spróbuj:

console.dir(clickEvents);

Lub

console.dir(window);
 12
Author: Michael Butler,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-29 17:41:42

Opera 12 (nie najnowszy silnik Chrome Webkit oparty) Dragonfly ma to od jakiegoś czasu i jest oczywiście wyświetlana w strukturze DOM. Moim zdaniem jest to lepszy debugger i jest jedynym powodem, dla którego nadal używam wersji opartej na Operze 12 (nie ma wersji v13, v14 i V15 Webkit nie ma nadal Dragonfly) {]}

Tutaj wpisz opis obrazka

 7
Author: Daniel Sokolowski,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-11-28 16:30:26

W pełni działające rozwiązanie oparte na odpowiedzi Jana Turona - zachowuje się jak getEventListeners() z konsoli:

(jest mały błąd z duplikatami. I tak niewiele się psuje.)

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

Użycie:

someElement.getEventListeners([name]) - return list of Event Listener, if name is set Return array of listener for that event

someElement.clearEventListeners([name]) - Usuń wszystkie słuchacze zdarzeń, jeśli nazwa jest ustawiona, Usuń słuchacze dla tego zdarzenia

 7
Author: n00b,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:26:38

Prototype 1.7.1 way

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
Author: Ronald,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-01-17 17:28:55

Próbuję to zrobić w jQuery 2.1, a przy metodzie "$().click() -> $(element).data("events").click; " to nie działa.

Zdałem sobie sprawę, że tylko $.Funkcje _data () działają w moim przypadku :

	$(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
Author: Joel Barba,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-19 09:00:35

Istnieje ładne jQuery Events extension :

Tutaj wpisz opis obrazka (temat źródło )

 1
Author: T.Todua,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:34:45

Ostatnio pracowałem z wydarzeniami i chciałem wyświetlić / kontrolować wszystkie zdarzenia na stronie. Po przyjrzeniu się możliwym rozwiązaniom postanowiłem pójść własną drogą i stworzyć własny system do monitorowania zdarzeń. Zrobiłem trzy rzeczy.

Najpierw potrzebowałem kontenera dla wszystkich detektorów zdarzeń na stronie: to jest obiektEventListeners. Ma trzy przydatne metody: add(), remove(), i get().

Następnie utworzyłem EventListener obiekt, który przechowuje niezbędne informacje dla zdarzenia, tj.: target, type, callback, options, useCapture, wantsUntrusted, i dodano metodę remove(), aby usunąć słuchacza.

Na koniec rozszerzyłem natywne metody addEventListener() i removeEventListener(), aby działały z obiektami, które stworzyłem (EventListener i EventListeners).

Użycie:

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

// bodyClickEvent.remove();

addEventListener() tworzy obiekt EventListener, dodaje go do EventListeners i zwraca obiekt EventListener, dzięki czemu można go później usunąć.

EventListeners.get() może być używany do wyświetlania słuchaczy na stronie. Przyjmuje EventTarget lub string (event Typ).

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

Demo

Powiedzmy, że chcemy znać każdy detektor zdarzeń na bieżącej stronie. Możemy to zrobić (zakładając, że używasz rozszerzenia menedżera skryptów, w tym przypadku Tampermonkey). Następujący skrypt robi to:

// ==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);
A kiedy wymienimy wszystkich słuchaczy, pisze, że jest 299 słuchaczy. Wydaje się, że są jakieś duplikaty, ale nie wiem, czy naprawdę są duplikaty. Nie każdy typ zdarzenia jest duplikowany, więc wszystkie te " duplikaty" może być indywidualnym słuchaczem.

zrzut ekranu konsoli z listą wszystkich słuchaczy zdarzeń na tej stronie

Kod można znaleźć w moim repozytorium . nie chciałem tego tutaj umieszczać, ponieważ jest dość długi.


Update: to nie działa z jQuery. Kiedy badam EventListener, widzę, że wywołanie zwrotne jest

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

Wierzę, że to należy do jQuery, a nie jest rzeczywistym callback. jQuery przechowuje rzeczywiste wywołanie zwrotne we właściwościach EventTarget:

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

Tutaj wpisz opis obrazka

Aby usunąć detektor zdarzeń, rzeczywiste wywołanie zwrotne musi zostać przekazane do metody removeEventListener(). Więc aby to działało z jQuery, wymaga dalszej modyfikacji. Może naprawię to w przyszłości.

 0
Author: akinuri,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-28 10:33:33