it-swarm.com.ru

Как найти слушателей событий на узле DOM при отладке или из кода JavaScript?

У меня есть страница, где некоторые слушатели событий прикреплены к полям ввода и полям выбора. Есть ли способ узнать, какие слушатели событий наблюдают за конкретным узлом DOM и для какого события?

События прикрепляются с использованием:

  1. ПрототипEvent.observe;
  2. DOM's addEventListener;
  3. В качестве атрибута элемента element.onclick.
739
Navneet

Если вам просто нужно проверить, что происходит на странице, вы можете попробовать Visual Event bookmarklet.

Update: Визуальное событие 2 доступно;

485
Andrew Hedges

Это зависит от того, как прикреплены события. Для иллюстрации предположим, что у нас есть следующий обработчик кликов:

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

Мы собираемся прикрепить его к нашему элементу, используя разные методы, некоторые из которых позволяют проверять, а некоторые нет.

Метод А) один обработчик события

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

Метод Б) несколько обработчиков событий

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

Метод 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 (хранит обработчик внутри объекта)

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

(См. jQuery.fn.data и jQuery.data )

Метод D): прототип (грязный)

$(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 включительно (тут очень сложно получилось)

    // 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 (немного лучше)

    // 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 и Safari поддерживают функцию getEventListeners(domElement) в консоли инструментов разработчика.

Для большинства целей отладки это можно использовать. 

Ниже очень хорошая ссылка для его использования: https://developers.google.com/chrome-developer-tools/docs/commandline-api#geteventlistenersobject

233
Raghav

Инспектор WebKit в браузерах Chrome или Safari теперь делает это. Он отобразит прослушиватели событий для элемента DOM, когда вы выберете его на панели «Элементы».

85
Ishan

Можно перечислить всех слушателей событий в JavaScript: это не так сложно; вам просто нужно взломать метод prototype HTML-элементов (перед добавлением слушателей).

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

Теперь каждый элемент привязки (a) будет иметь свойство lastListenerInfo, которое содержит всех своих слушателей. И это даже работает для удаления слушателей с анонимными функциями.

65
Ivan Castellanos

(Переписываем ответ от этот вопрос так как он актуален здесь.)

При отладке, если вы просто хотите увидеть события, я рекомендую либо ... 

  1. Визуальное событие
  2. Раздел Elements в инструментах разработчика Chrome: выберите элемент и найдите «Слушатели событий» в правом нижнем углу (аналогично в Firefox)

Если вы хотите использовать события в своем коде и используете jQuery до версии 1.8, вы можете использовать: 

$(selector).data("events")

чтобы получить события. Начиная с версии 1.8, использование .data ("events") более не поддерживается (см. этот тикет об ошибке ). Ты можешь использовать:

$._data(element, "events")

Другой пример: записать все события кликов по определенной ссылке в консоли:

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

(см. http://jsfiddle.net/HmsQC/ для рабочего примера)

К сожалению, с использованием данных $ ._ это не рекомендуется, за исключением отладки, поскольку она является внутренней структурой jQuery и может измениться в будущих выпусках. К сожалению, я не знаю других легких способов доступа к событиям.

40
Luke

Используйте getEventListeners в Google Chrome :

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

1: Prototype.observe использует Element.addEventListener (см. исходный код )

2: Вы можете переопределить Element.addEventListener, чтобы запомнить добавленные прослушиватели (удобное свойство EventListenerList было удалено из предложения спецификации DOM3). Запустите этот код, прежде чем какое-либо событие будет прикреплено:

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

Читать все события по:

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

И не забудьте переопределить Element.removeEventListener, чтобы удалить событие из пользовательского Element.eventListenerList.

3: свойство Element.onclick здесь требует особого внимания:

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

4: не забывайте атрибут содержимого Element.onclick: это две разные вещи:

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

Так что вам тоже нужно с этим справиться:

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

Букмарклет Visual Event (упомянутый в самом популярном ответе) крадет только кеш пользовательской библиотеки:

Оказывается, что нет никакого стандартного метода, обеспеченного W3C Рекомендуемый интерфейс DOM, чтобы узнать, какие слушатели событий прикреплен к определенному элементу. Хотя это может показаться Надзор, было предложение включить свойство под названием eventListenerList к спецификации DOM уровня 3, но был к сожалению был удален в более поздних черновиках. Как таковой, мы вынуждены посмотрел на отдельные библиотеки Javascript, которые обычно поддерживать кеш прикрепленных событий (чтобы их потом можно было удалить и выполнить другие полезные абстракции).

Таким образом, чтобы визуальное событие отображало события, оно должно иметь возможность проанализировать информацию о событии из библиотеки Javascript.

Переопределение элементов может быть сомнительным (т. Е. Потому, что есть некоторые специфические функции DOM, такие как живые коллекции, которые не могут быть закодированы в JS), но он изначально поддерживает EventListenerList и работает в Chrome, Firefox и Opera (не работает в IE7 ).

25
Jan Turoň

Вы можете обернуть нативные методы DOM для управления слушателями событий, поместив это в верхнюю часть вашего <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
Jon z

Инструменты разработчика Firefox теперь делают это. События отображаются нажатием кнопки «ev» справа от каждого элемента, включая события jQuery и DOM .

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

18
simonzack

Если у вас есть Firebug , вы можете использовать console.dir(object or array) для печати дерева Nice в журнале консоли любого скаляра, массива или объекта JavaScript. 

Пытаться: 

console.dir(clickEvents);

или же

console.dir(window);
12
Michael Butler

Полностью рабочее решение, основанное на ответе Яна Турона - ведет себя как getEventListeners() из консоли:

(Есть небольшая ошибка с дубликатами. В любом случае, она не сильно ломается.)

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

Использование:

someElement.getEventListeners([name]) - возвращает список слушателей события, если установлено имя, возвращает массив слушателей для этого события.

someElement.clearEventListeners([name]) - удалить все прослушиватели событий, если задано имя, удалить только прослушиватели для этого события

7
n00b

Opera 12 (не последняя версия на основе движка Chrome Webkit) Dragonfly имеет это некоторое время и, очевидно, отображается в структуре DOM. На мой взгляд, это превосходный отладчик, и это единственная причина, почему я до сих пор использую версию для Opera 12 (версии v13, v14 нет, а в версии 15 для Webkit по-прежнему отсутствует Dragonfly)

enter image description here

7
Daniel Sokolowski

Прототип 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

Существует хорошее расширение jQuery Events:

 enter image description here (тема источник )

3
T.Todua

Я пытаюсь сделать это в jQuery 2.1, и с помощью метода $().click() -> $(element).data("events").click; это не работает.

Я понял, что в моем случае работают только функции $ ._ data ():

	$(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

изменение этих функций позволит вам регистрировать добавленные слушатели:

EventTarget.prototype.addEventListener
EventTarget.prototype.attachEvent
EventTarget.prototype.removeEventListener
EventTarget.prototype.detachEvent

читать остальных слушателей с

console.log(someElement.onclick);
console.log(someElement.getAttribute("onclick"));
0
Aiden Waterman

Я недавно работал с событиями и хотел просмотреть/контролировать все события на странице. Посмотрев на возможные решения, я решил пойти своим путем и создать собственную систему мониторинга событий. Итак, я сделал три вещи.

Во-первых, мне был нужен контейнер для всех прослушивателей событий на странице: это объект EventListeners. Он имеет три полезных метода: add(), remove() и get().

Затем я создал объект EventListener для хранения необходимой информации о событии, т.е. target, type, callback, options, useCapture, wantsUntrusted, и добавил метод remove() для удаления прослушивателя.

Наконец, я расширил родные методы addEventListener() и removeEventListener(), чтобы они работали с объектами, которые я создал (EventListener и EventListeners).

Использование:

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

// bodyClickEvent.remove();

addEventListener() создает объект EventListener, добавляет его в EventListeners и возвращает объект EventListener, чтобы его можно было удалить позже.

EventListeners.get() может использоваться для просмотра слушателей на странице. Он принимает EventTarget или строку (тип события).

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

Демо

Допустим, мы хотим знать каждого слушателя событий на этой текущей странице. Мы можем сделать это (при условии, что вы используете расширение диспетчера сценариев, в данном случае Tampermonkey). Следующий скрипт делает это:

// ==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);

И когда мы перечисляем всех слушателей, он говорит, что есть 299 слушателей событий. «Кажется» есть некоторые дубликаты, но я не знаю, действительно ли они дубликаты. Не каждый тип события дублируется, поэтому все эти «дубликаты» могут быть отдельным слушателем.

 screenshot of console listing all event listeners in this page

Код можно найти в моем хранилище. Я не хотел размещать это здесь, потому что это довольно долго.


Update: Это не похоже на работу с jQuery. Когда я проверяю EventListener, я вижу, что обратный вызов

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

Я считаю, что это принадлежит JQuery, а не фактический обратный вызов. jQuery сохраняет фактический обратный вызов в свойствах EventTarget:

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

 enter image description here

Чтобы удалить прослушиватель событий, фактический обратный вызов должен быть передан методу removeEventListener(). Так что для того, чтобы заставить это работать с jQuery, он нуждается в дальнейшей модификации. Я мог бы исправить это в будущем.

0
akinuri