Как найти прослушиватели событий на узле DOM при отладке или из кода JavaScript?
у меня есть страница, где некоторые прослушиватели событий прикреплены к полям ввода и выберите поля. Есть ли способ узнать, какие прослушиватели событий наблюдают за определенным узлом DOM и для какого события?
события прикрепляются с помощью:
-
прототипа!--10-->
Event.observe
; - дома
addEventListener
; - как атрибут элемента
element.onclick
.
17 ответов
Если вам просто нужно проверить, что происходит на странице, вы могли бы попробовать Визуальное Событие букмарклет.
обновление: Визуальное Событие 2 существующих;
это зависит от того, как прикреплены события. Для иллюстрации предположим, что у нас есть следующий обработчик щелчка:
var handler = function() { alert('clicked!') };
мы собираемся присоединить его к нашему элементу, используя различные методы, некоторые из которых позволяют проверку, а некоторые нет.
метод A) один обработчик событий
element.onclick = handler;
// inspect
alert(element.onclick); // alerts "function() { alert('clicked!') }"
метод B) несколько обработчиков событий
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!') }" })
поддержка Chrome, Firefox, Vivaldi и Safari getEventListeners(domElement)
в консоли инструментов разработчика.
для большинства целей отладки это можно использовать.
ниже очень хорошая ссылка для его использования: https://developers.google.com/chrome-developer-tools/docs/commandline-api#geteventlistenersobject
инспектор 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
свойство, которое содержит все его слушатели. И он даже работает для удаления слушателей с анонимными функциями.
(переписывая ответ из этот вопрос поскольку это актуально здесь.)
при отладке, если вы просто хотите увидеть события, я рекомендую либо...
- Визуальное Событие
- на элементов раздел инструментов разработчика Chrome: выберите элемент и найдите "прослушиватели событий" в правом нижнем углу (аналогично Firefox)
Если вы хотите использовать события в коде, и вы используете jQuery до версии 1.8, вы можете использовать:
$(selector).data("events")
чтобы получить события. начиная с версии 1.8, используя .данные ("события") прекращаются (см. этот билет ошибка). Вы можете использовать:
$._data(element, "events")
другой пример: запишите все события клика по определенной ссылке на консоль:
var $myLink = $('a.myClass');
console.log($._data($myLink[0], "events").click);
(см. http://jsfiddle.net/HmsQC/ рабочий пример)
к сожалению, используя $._данные это не рекомендуется за исключением отладки, поскольку это внутренняя структура jQuery и может измениться в будущих выпусках. К сожалению, я не знаю других простых способов доступа к событиям.
используйте getEventListeners в Google Chrome:
getEventListeners(document.getElementByID('btnlogin'));
getEventListeners($('#btnlogin'));
1: Prototype.observe
использует элемент.метод addEventListener (см. исходный код)
2: Вы можете переопределить Element.addEventListener
запомнить добавленных слушателей (удобное свойство EventListenerList
был удален из предложения DOM3 spec). Запустите этот код перед подключением любого события:
(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: нужна собственность особый уход здесь:
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);
букмарклет визуальных событий (упомянутый в самом популярном ответе) только крадет кэш обработчика пользовательских библиотек:
оказывается, что нет стандартного метода, предусмотренного W3C рекомендуемый интерфейс DOM, чтобы узнать, какие прослушиватели событий прикрепленный к определенному элементу. Хотя это может показаться надзор, было предложение включить свойство под названием eventListenerList к спецификации DOM уровня 3, но был к сожалению, были удалены в более поздних проектов. Как таковые мы вынуждены посмотрел на отдельные библиотеки Javascript, которые обычно ведение кэша вложенных событий (чтобы впоследствии их можно было удалить и выполнять другие полезные абстракции).
как таковой, для визуального события к показывать события, он должен уметь проанализируйте информацию о событии из библиотеки Javascript.
переопределение элементов может быть сомнительным (т. е. потому, что есть некоторые особенности DOM, такие как живые коллекции, которые не могут быть закодированы в JS), но он дает поддержку eventListenerList изначально, и он работает в Chrome, Firefox и Opera (не работает в IE7).
вы можете обернуть собственные методы 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
Если у вас Палий, вы можете использовать console.dir(object or array)
для печати хорошего дерева в журнале консоли любого скаляра JavaScript, массива или объекта.
попробуй:
console.dir(clickEvents);
или
console.dir(window);
Opera 12 (не последний движок Chrome Webkit) Стрекоза имеет это некоторое время и, очевидно, отображается в структуре DOM. На мой взгляд, это превосходный отладчик, и это единственная причина, по которой я все еще использую версию Opera 12 (нет версии v13, v14, а в V15 Webkit все еще не хватает Dragonfly)
полностью рабочее решение на основе ответ Яна Турона - ведет себя как 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])
- удалить все прослушиватели событий, если имя установлено только удалить прослушиватели для этого события
прототип 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];
}
Я пытаюсь сделать это в 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>
недавно я работал с событиями и хотел просмотреть/контролировать все события на странице. Посмотрев на возможные решения, я решил пойти своим путем и создать собственную систему для мониторинга событий. Итак, я сделал три вещи.
во-первых, мне нужен контейнер для всех прослушивателей событий на странице: это