jQuery查找注册对象的事件处理程序

我需要找到在对象上注册了哪些事件处理程序。

例如:

$("#el").click(function() {...});
$("#el").mouseover(function() {...});

$("#el")已经注册了点击鼠标移至

是否有一个函数来找出这一点,并可能遍历事件处理程序?

如果在jQuery对象上不能通过适当的方法实现,那么在普通DOM对象上可以吗?

478783 次浏览

从jQuery 1.8开始,事件数据不再从数据的“公共API”中可用。# EYZ0阅读。你现在应该使用这个:

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中)的方法是- # EYZ0 < / p >

下划线(“_”)是这里的区别所在。在内部,它调用$.data(element, name, null, true),最后一个(第四个)参数是一个内部参数(“pvt”)。

可以使用以下方法检索事件:

jQuery(elem).data('events');

或jQuery 1.8+:

jQuery._data(elem, 'events');

<强>注意: 使用$('selector').live('event', handler)绑定事件

jQuery(document).data('events')

为此我使用eventbug插件来firebug。

在1.9版本中,除了使用Migrate插件恢复旧的行为之外,还没有文档化的方法来检索事件。可以像jps提到的那样使用_.data()方法,但这是一个内部方法。所以只要做正确的事情,如果你需要这个功能,就使用Migrate插件。

来自jQuery文档.data("events")

在1.9之前,.data("events")可以用来检索jQuery的 如果没有其他元素,则为元素的未记录的内部事件数据结构 代码定义了一个名为“events”的数据元素。这个特殊的 Case在1.9中被移除。没有可检索的公共接口 这个内部数据结构,它仍然没有文档。然而, jQuery Migrate插件为依赖的代码恢复此行为 。< / p >

无耻的插头,但你可以使用< >强findHandlerJS < / >强

要使用它,你只需要包括findHandlersJS(或只是复制&粘贴原始javascript代码到chrome的控制台窗口),并指定事件类型和jquery选择器的元素,你感兴趣的。

对于您的示例,您可以通过执行下面的操作快速找到您提到的事件处理程序

findEventHandlers("click", "#el")
findEventHandlers("mouseover", "#el")

这是返回的结果:

    <李>元素< br > 在中注册事件处理程序的实际元素 <李> < br >事件 包含我们感兴趣的事件类型的jquery事件处理程序信息的数组(例如,单击,更改等)
      <李>处理< br > 您可以通过右键单击它并选择Show function definition来查看实际的事件处理程序方法 <李>选择< br > 选择器为委托事件提供。对于直接事件,它将为空 <李> < br >目标 带有此事件处理程序目标的元素的列表。例如,对于在文档对象中注册并以页面中的所有按钮为目标的委托事件处理程序,此属性将列出页面中的所有按钮。你可以悬停它们,并在chrome浏览器中高亮显示它们 李< / ul > < / >

    你可以试试这里<强> < / >强

在带有ECMAScript 5.1 / Array.prototype.map的现代浏览器中,也可以使用

jQuery._data(DOCUMENTELEMENT,'events')["EVENT_NAME"].map(function(elem){return elem.handler;});

在浏览器控制台中,它将打印以逗号分隔的处理程序的源。用于查看在特定事件上正在运行的所有内容。

我不得不说,许多答案都很有趣,但最近我遇到了一个类似的问题,解决方案非常简单,就是采用DOM方式。这是不同的,因为你不迭代,而是直接针对你需要的事件,但下面我将给出一个更一般的答案。

我有一排图片:

<table>
<td><tr><img class="folder" /></tr><tr>...</tr></td>
</table>

那个图像有一个点击事件处理器附加到它上面:

imageNode.click(function () { ... });

我的意图是将可点击区域扩展到整个行,所以我首先获得所有图像和相关行:

tableNode.find("img.folder").each(function () {
var tr;


tr = $(this).closest("tr");
// <-- actual answer
});

现在在实际出全新行中,我只是这样做了,给出了原始问题的答案:

tr.click(this.onclick);

因此,我直接从DOM元素获取事件处理程序,并将其放入jQuery单击事件处理程序中。效果非常好。

现在来看一般情况。在以前的jquery时代,你可以通过道格拉斯Crockford赋予我们的两个简单而强大的函数将所有事件附加到一个对象上:

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

我将@jps的两个解决方案组合到一个函数中:

jQuery.fn.getEvents = function() {
if (typeof(jQuery._data) === 'function') {
return jQuery._data(this.get(0), 'events') || {};
}


// jQuery version < 1.7.?
if (typeof(this.data) === 'function') {
return this.data('events') || {};
}


return {};
};

但是要注意,这个函数只能返回使用jQuery本身设置的事件。

另一种方法是使用jQuery来抓取元素,然后通过实际的Javascript来获取、设置和使用事件处理程序。例如:

var oldEventHandler = $('#element')[0].onclick;
// Remove event handler
$('#element')[0].onclick = null;
// Switch it back
$('#element')[0].onclick = oldEventHandler;

我创建了一个自定义的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)")

这将返回附加了单击处理程序的元素。

检查元素上的事件:

var events = $._data(element, "events")

注意,如果使用$(document),这将只适用于直接事件处理程序。on("event-name", "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])

我结合了上面的一些答案,创建了这个看起来疯狂但实用的脚本,希望它能列出给定元素上的大多数事件侦听器。请在这里进行优化。

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>

jQuery并不是让你简单地访问给定元素的事件。 您可以使用未记录的内部方法

访问它们
$._data(element, "events")

但它仍然不会给你所有的事件,准确地说不会显示分配给你的事件

$([selector|element]).on()


这些事件存储在文档中,因此您可以通过浏览来获取它们

$._data(document, "events")

但这是一个艰苦的工作,因为有整个网页的事件。

Tom G上面创建了一个函数,该函数只过滤给定元素的事件,并合并两个方法的输出,但它在输出中有重复事件的缺陷(并且有效地在元素的jQuery内部事件列表上混淆了应用程序)。 我修复了这个缺陷,你可以在下面找到代码。只需将其粘贴到开发控制台或应用程序代码中,并在需要时执行它,以获得给定元素的所有事件的良好列表。< / p >

需要注意的是,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;
}