JQuery найти обработчики событий, зарегистрированных с объектом
Мне нужно найти, какие обработчики событий зарегистрированы для объекта.
Например:
$("#el").click(function() {...});
$("#el").mouseover(function() {...});
$("#el")
зарегистрирован клик и наведение мыши.
Есть ли функция, чтобы выяснить это и, возможно, перебрать обработчики событий?
Если это невозможно для объекта jQuery с помощью соответствующих методов, возможно ли это для простого объекта DOM?
14 ответов
Начиная с jQuery 1.8, данные событий больше не доступны из "публичного API" для данных. Прочитайте этот пост в блоге jQuery. Теперь вы должны использовать это вместо:
jQuery._data( elem, "events" );
elem
должен быть элементом HTML, а не объектом jQuery или селектором.
Обратите внимание, что это внутренняя, "частная" структура, которая не должна изменяться. Используйте это только для целей отладки.
В более старых версиях jQuery вам, возможно, придется использовать старый метод:
jQuery( elem ).data( "events" );
Вы можете сделать это, сканируя события (начиная с jQuery 1.8+), например так:
$.each($._data($("#id")[0], "events"), function(i, event) {
// i is the event type, like "click"
$.each(event, function(j, h) {
// h.handler is the function being called
});
});
Вот пример, с которым вы можете играть:
$(function() {
$("#el").click(function(){ alert("click"); });
$("#el").mouseover(function(){ alert("mouseover"); });
$.each($._data($("#el")[0], "events"), function(i, event) {
output(i);
$.each(event, function(j, h) {
output("- " + h.handler);
});
});
});
function output(text) {
$("#output").html(function(i, h) {
return h + text + "<br />";
});
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="el">Test</div>
<code>
<span id="output"></span>
</code>
В jQuery 1.8+ это больше не будет работать, поскольку внутренние данные помещены в другой объект.
Последний неофициальный (но работает и в предыдущих версиях, по крайней мере в 1.7.2) способ сделать это сейчас -$._data(element, "events")
Подчеркивание ("_") - вот что здесь имеет значение. Внутренне это зовет $.data(element, name, null, true)
последний (четвертый) параметр является внутренним ("pvt").
Бесстыдная вилка, но вы можете использовать findHandlerJS
Чтобы использовать его, вам просто нужно включить findHandlersJS (или просто скопировать и вставить необработанный код JavaScript в окно консоли Chrome) и указать тип события и селектор jquery для интересующих вас элементов.
Для вашего примера вы можете быстро найти обработчики событий, которые вы упомянули, выполнив
findEventHandlers("click", "#el")
findEventHandlers("mouseover", "#el")
Вот что возвращается:
- элемент
Фактический элемент, в котором обработчик события был зарегистрирован в - События
Массив с информацией об обработчиках событий jquery для интересующего нас типа события (например, щелчок, изменение и т. Д.)- обработчик
Фактический метод обработчика событий, который вы можете увидеть, щелкнув его правой кнопкой мыши и выбрав Показать определение функции - селектор
Селектор для делегированных событий. Это будет пусто для прямых событий. - цели
Список с элементами, на которые нацелен этот обработчик событий. Например, для делегированного обработчика событий, который зарегистрирован в объекте документа и предназначается для всех кнопок на странице, это свойство будет перечислять все кнопки на странице. Вы можете навести их и увидеть, что они выделены хромом.
- обработчик
Вы можете попробовать это здесь
Я объединил оба решения из @jps в одну функцию:
jQuery.fn.getEvents = function() {
if (typeof(jQuery._data) == 'function') {
return jQuery._data(this.get(0), 'events') || {};
} else if (typeof(this.data) == 'function') { // jQuery version < 1.7.?
return this.data('events') || {};
}
return {};
};
Но будьте осторожны, эта функция может возвращать только события, которые были установлены с использованием самого jQuery.
Чтобы проверить события на элементе:
var events = $._data(element, "events")
Обратите внимание, что это будет работать только с прямыми обработчиками событий, если вы используете $(document).on("имя-события", "jq-selector", function() { //logic }), вы захотите увидеть Функция getEvents внизу этого ответа
Например:
var events = $._data(document.getElementById("myElemId"), "events")
или же
var events = $._data($("#myElemId")[0], "events")
Полный пример:
<html>
<head>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.0/jquery.min.js" type="text/javascript"></script>
<script>
$(function() {
$("#textDiv").click(function() {
//Event Handling
});
var events = $._data(document.getElementById('textDiv'), "events");
var hasEvents = (events != null);
});
</script>
</head>
<body>
<div id="textDiv">Text</div>
</body>
</html>
Более полный способ проверки, включающий динамические слушатели, установленные с помощью $ (document).on
function getEvents(element) {
var elemEvents = $._data(element, "events");
var allDocEvnts = $._data(document, "events");
for(var evntType in allDocEvnts) {
if(allDocEvnts.hasOwnProperty(evntType)) {
var evts = allDocEvnts[evntType];
for(var i = 0; i < evts.length; i++) {
if($(element).is(evts[i].selector)) {
if(elemEvents == null) {
elemEvents = {};
}
if(!elemEvents.hasOwnProperty(evntType)) {
elemEvents[evntType] = [];
}
elemEvents[evntType].push(evts[i]);
}
}
}
}
return elemEvents;
}
Пример использования:
getEvents($('#myElemId')[0])
Начиная с версии 1.9, нет документированного способа получения событий, кроме использования плагина Migrate для восстановления старого поведения. Вы можете использовать метод _.data(), как упоминает jps, но это внутренний метод. Так что просто сделайте правильно и используйте плагин Migrate, если вам нужна эта функциональность.
Из документации по jQuery .data("events")
До версии 1.9.data("события") можно было использовать для получения недокументированной структуры данных внутреннего события jQuery для элемента, если никакой другой код не определил элемент данных с именем "события". Этот особый случай был удален в 1.9. Не существует общедоступного интерфейса для извлечения этой внутренней структуры данных, и она остается недокументированной. Однако плагин jQuery Migrate восстанавливает это поведение для кода, который зависит от него.
Я создал пользовательский селектор jQuery, который проверяет как кеш jQuery назначенных обработчиков событий, так и элементы, которые используют собственный метод для их добавления:
(function($){
$.find.selectors[":"].event = function(el, pos, match) {
var search = (function(str){
if (str.substring(0,2) === "on") {str = str.substring(2);}
return str;
})(String(match[3]).trim().toLowerCase());
if (search) {
var events = $._data(el, "events");
return ((events && events.hasOwnProperty(search)) || el["on"+search]);
}
return false;
};
})(jQuery);
Пример:
$(":event(click)")
Это вернет элементы, к которым прикреплен обработчик кликов.
В современном браузере с ECMAScript 5.1 / Array.prototype.map
Вы также можете использовать
jQuery._data(DOCUMENTELEMENT,'events')["EVENT_NAME"].map(function(elem){return elem.handler;});
в консоли браузера, которая будет печатать исходные тексты обработчиков, через запятую. Полезно, чтобы взглянуть на то, что все работает на конкретном событии.
События могут быть получены с помощью:
jQuery(elem).data('events');
или jQuery 1.8+:
jQuery._data(elem, 'events');
Примечание: события ограничены с помощью $('selector').live('event', handler)
можно получить с помощью:
jQuery(document).data('events')
J Query не позволяет вам просто получить доступ к событиям для данного элемента. Вы можете получить к ним доступ, используя недокументированный внутренний метод
$._data(element, "events")
Но он все равно не покажет вам все события, а точнее не покажет вам события, назначенные с
$([selector|element]).on()
Эти события хранятся внутри документа, поэтому вы можете получить их, просмотрев
$._data(document, "events")
но это тяжелая работа, поскольку есть события для всей веб-страницы.
Том G выше создал функцию, которая фильтрует документ только для событий данного элемента и объединяет вывод обоих методов, но у него был недостаток, заключающийся в дублировании событий в выводе (и, фактически, во внутреннем списке событий jQuery элемента, мешающем с вашим приложением). Я исправил этот недостаток, и вы можете найти код ниже. Просто вставьте его в консоль разработчика или в код своего приложения и выполните его при необходимости, чтобы получить хороший список всех событий для данного элемента.
Важно отметить, что element на самом деле является HTMLElement, а не объектом jQuery.
function getEvents(element) {
var elemEvents = $._data(element, "events");
var allDocEvnts = $._data(document, "events");
function equalEvents(evt1, evt2)
{
return evt1.guid === evt2.guid;
}
for(var evntType in allDocEvnts) {
if(allDocEvnts.hasOwnProperty(evntType)) {
var evts = allDocEvnts[evntType];
for(var i = 0; i < evts.length; i++) {
if($(element).is(evts[i].selector)) {
if(elemEvents == null) {
elemEvents = {};
}
if(!elemEvents.hasOwnProperty(evntType)) {
elemEvents[evntType] = [];
}
if(!elemEvents[evntType].some(function(evt) { return equalEvents(evt, evts[i]); })) {
elemEvents[evntType].push(evts[i]);
}
}
}
}
}
return elemEvents;
}
Я должен сказать, что многие ответы интересны, но недавно у меня возникла похожая проблема, и решение было очень простым, если идти по DOM. Это отличается тем, что вы не повторяете, а целитесь непосредственно в нужное вам событие, но ниже я дам более общий ответ.
У меня было изображение в ряд:
<table>
<td><tr><img class="folder" /></tr><tr>...</tr></td>
</table>
И к этому изображению был прикреплен обработчик события click:
imageNode.click(function () { ... });
Мое намерение состояло в том, чтобы расширить область, активируемую кликами, на всю строку, поэтому сначала я получил все изображения и относительные строки
tableNode.find("img.folder").each(function () {
var tr;
tr = $(this).closest("tr");
// <-- actual answer
});
Теперь в фактической строке ответа я просто сделал следующее, дав ответ на оригинальный вопрос:
tr.click(this.onclick);
Поэтому я извлек обработчик событий непосредственно из элемента DOM и поместил его в обработчик событий щелчка jQuery. Работает как шарм.
Теперь к общему случаю. В прежние дни до jQuery вы могли привязать все события к объекту с помощью двух простых, но мощных функций, подаренных нам, смертным, Дугласом Крокфордом:
function walkTheDOM(node, func)
{
func(node);
node = node.firstChild;
while (node)
{
walkTheDOM(node, func);
node = node.nextSibling;
}
}
function purgeEventHandlers(node)
{
walkTheDOM(node, function (n) {
var f;
for (f in n)
{
if (typeof n[f] === "function")
{
n[f] = null;
}
}
});
}
Попробуйте плагин jquery отладчик, если вы используете Chrome: https://chrome.google.com/webstore/detail/jquery-debugger/dbhhnnnpaeobfddmlalhnehgclcmjimi?hl=en
Другой способ сделать это - просто использовать jQuery для захвата элемента, а затем пройти через настоящий Javascript, чтобы получить, установить и поиграть с обработчиками событий. Например:
var oldEventHandler = $('#element')[0].onclick;
// Remove event handler
$('#element')[0].onclick = null;
// Switch it back
$('#element')[0].onclick = oldEventHandler;
Я объединил некоторые из приведенных выше ответов и создал этот сумасшедший, но функциональный сценарий, который, надеюсь, перечисляет большинство прослушивателей событий для данного элемента. Не стесняйтесь оптимизировать его здесь.
var element = $("#some-element");
// sample event handlers
element.on("mouseover", function () {
alert("foo");
});
$(".parent-element").on("mousedown", "span", function () {
alert("bar");
});
$(document).on("click", "span", function () {
alert("xyz");
});
var collection = element.parents()
.add(element)
.add($(document));
collection.each(function() {
var currentEl = $(this) ? $(this) : $(document);
var tagName = $(this)[0].tagName ? $(this)[0].tagName : "DOCUMENT";
var events = $._data($(this)[0], "events");
var isItself = $(this)[0] === element[0]
if (!events) return;
$.each(events, function(i, event) {
if (!event) return;
$.each(event, function(j, h) {
var found = false;
if (h.selector && h.selector.length > 0) {
currentEl.find(h.selector).each(function () {
if ($(this)[0] === element[0]) {
found = true;
}
});
} else if (!h.selector && isItself) {
found = true;
}
if (found) {
console.log("################ " + tagName);
console.log("event: " + i);
console.log("selector: '" + h.selector + "'");
console.log(h.handler);
}
});
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="parent-element">
<span id="some-element"></span>
</div>