У меня есть страница, где некоторые слушатели событий прикреплены к полям ввода и полям выбора. Есть ли способ узнать, какие слушатели событий наблюдают за конкретным узлом DOM и для какого события?
События прикрепляются с использованием:
- Прототип
Event.observe
; - DOM's
addEventListener
; - Как атрибут элемента
element.onclick
.
Если вам просто нужно проверить, что происходит на странице, вы можете попробовать букмарклет Visual Event .
Обновление : доступно визуальное событие 2
EventBug
плагин Firebug . Это зависит от того, как прикреплены события. Для иллюстрации предположим, что у нас есть следующий обработчик кликов:
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!') }" })
addEventListener
? .data('events')
как это было раньше. Чтобы получить доступ к внутренним данным события, используйте $._data(elem, 'events')
. Обратите внимание, что эта функция помечена «только для внутреннего использования» в исходном коде jQuery, поэтому нет никаких обещаний, что она всегда будет работать в будущем, но я считаю, что она работает с jQuery 1.7 и работает до сих пор. Если у вас есть Firebug , вы можете использовать console.dir(object or array)
для печати хорошего дерева в журнале консоли любого скаляра JavaScript, массива или объекта.
Пытаться:
console.dir(clickEvents);
или
console.dir(window);
Инспектор WebKit в браузерах Chrome или Safari теперь делает это. Он отобразит прослушиватели событий для элемента DOM, когда вы выберете его на панели элементов.
Можно перечислить всех слушателей событий в 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
свойство, содержащее всех его слушателей. И это даже работает для удаления слушателей с анонимными функциями.
Node.prototype
вместо этого? Вот откуда и HTMLAnchorElement
наследует .addEventListener
. (Переписать ответ на этот вопрос, поскольку он уместен здесь.)
При отладке, если вы просто хотите увидеть события, я рекомендую либо ...
- Визуальное событие
- Раздел « Элементы » инструментов разработчика Chrome: выберите элемент и найдите «Прослушиватели событий» в правом нижнем углу (аналогично в Firefox)
Если вы хотите использовать события в своем коде и используете jQuery до версии 1.8 , вы можете использовать:
$(selector).data("events")
чтобы получить события. Начиная с версии 1.8, использование .data («события») прекращено (см. Этот тикет об ошибке ). Ты можешь использовать:
$._data(element, "events")
Другой пример: записать все события кликов по определенной ссылке в консоли:
var $myLink = $('a.myClass');
console.log($._data($myLink[0], "events").click);
(см. http://jsfiddle.net/HmsQC/ для рабочего примера)
К сожалению, при использовании данных $ ._ это не рекомендуется, за исключением отладки, поскольку это внутренняя структура jQuery, и она может измениться в будущих выпусках. К сожалению, я не знаю других легких способов доступа к событиям.
$._data(elem, "events")
не работает с jQuery 1.10, по крайней мере, для событий, зарегистрированных с использованием $(elem).on('event', ...)
. Кто-нибудь знает, как их отладить? $._data
может быть элемент, а не объект jQuery. Так что я должен исправить свой пример выше, чтобы бытьconsole.log($._data($myLink[0], "events").click);
Прототип 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];
}
Поддержка Chrome, Firefox, Vivaldi и Safari getEventListeners(domElement)
в консоли инструментов разработчика.
Для большинства целей отладки это можно использовать.
Ниже очень хорошая ссылка для его использования: https://developers.google.com/web/tools/chrome-devtools/console/utilities#geteventlisteners
getEventListeners(object)
obj getEventListeners()
var list = getEventListeners(document.getElementById("YOURIDHERE")); console.log(list["focus"][0]["listener"].toString())
. Измените «фокус» на событие, которое вы хотите проверить, и номер, если на одном событии присутствуют несколько слушателей. getEventListeners($0)
получите прослушиватели событий для элемента, на котором вы сосредоточены в инструментах разработчика Chrome. Я использую это все время. Не люблю использовать функции Opera 12 (не последняя версия на основе движка Chrome Webkit) Dragonfly некоторое время имела это и, очевидно, отображается в структуре DOM. На мой взгляд, это превосходный отладчик, и это единственная причина, по которой я до сих пор использую версию для Opera 12 (версии v13, v14 нет, а в версии 15 для Webkit по-прежнему отсутствует Dragonfly)
Используйте getEventListeners в Google Chrome :
getEventListeners(document.getElementByID('btnlogin'));
getEventListeners($('#btnlogin'));
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 ).
Я пытаюсь сделать это в 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>
Полностью рабочее решение, основанное на ответе Яна Турона - ведет себя как 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])
- удалить все прослушиватели событий, если установлено имя, удалить только прослушиватели для этого события
body
и document
элементах. Вы можете обернуть нативные методы 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
Существует хорошее расширение jQuery Events :
( источник темы )
Я недавно работал с событиями и хотел просмотреть / контролировать все события на странице. Посмотрев на возможные решения, я решил пойти своим путем и создать собственную систему мониторинга событий. Итак, я сделал три вещи.
Во-первых, мне был нужен контейнер для всех слушателей событий на странице: это EventListeners
объект. Она состоит из трех полезных методов: add()
, remove()
, и get()
.
Затем я создал EventListener
объект для хранения информации , необходимой для этого события, а именно: target
, type
, callback
, options
, useCapture
, wantsUntrusted
, и добавил метод remove()
для удаления слушателя.
Наконец, я расширил native 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 слушателей событий. «Кажется» есть некоторые дубликаты, но я не знаю, действительно ли они дубликаты. Не каждый тип события дублируется, поэтому все эти «дубликаты» могут быть отдельным слушателем.
Код можно найти в моем хранилище. Я не хотел размещать это здесь, потому что это довольно долго.
Обновление: это не похоже на работу с 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");
});
Чтобы удалить прослушиватель событий, фактический обратный вызов должен быть передан removeEventListener()
методу. Так что для того, чтобы заставить это работать с jQuery, он нуждается в дальнейшей модификации. Я мог бы исправить это в будущем.
изменение этих функций позволит вам регистрировать добавленные слушатели:
EventTarget.prototype.addEventListener
EventTarget.prototype.attachEvent
EventTarget.prototype.removeEventListener
EventTarget.prototype.detachEvent
читать остальных слушателей с
console.log(someElement.onclick);
console.log(someElement.getAttribute("onclick"));
element.addEventListener(type, callback, [bubble])
, при этом ониelement.onclick = function
будут перезаписываться при каждом назначении.