我需要找到在对象上注册了哪些事件处理程序。
例如:
$("#el").click(function() {...});
$("#el").mouseover(function() {...});
$("#el")
已注册 click 和 mouseover。
是否有一个函数可以找出它,并可能遍历事件处理程序?
如果通过适当的方法在 jQuery 对象上是不可能的,那么在普通的 DOM 对象上是否可能?
var events = (jQuery._data || jQuery.data)(elem, 'events');
从 jQuery 1.8 开始,事件数据不再可从“公共 API”获取数据。阅读this jQuery blog post。您现在应该改用它:
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); }); }); });函数输出(文本) { $("#output").html(函数(i, h) { return h + text + "
"; }); }
jQuery._data( jQuery("#el")[0], "events" );
而不是“公共数据”方法:jQuery("#el").data("events")
。 events
对象实际上已经很久没有存储在 .data()
中了,我们通过从“公共 API”中删除这个“代理”来修剪掉几个字节的代码
对于 jQuery 1.8+,这将不再起作用,因为内部数据被放置在不同的对象中。
最新的非官方(但也适用于以前的版本,至少在 1.7.2 中)现在的做法是 - $._data(element, "events")
下划线(“_”)在这里有所不同。在内部,它正在调用 $.data(element, name, null, true)
,最后一个(第四个)参数是一个内部参数(“pvt”)。
jQuery._data( element, "events" )
是现在获取此信息的“正确”方式。
无耻的插件,但你可以使用findHandlerJS
要使用它,您只需包含 findHandlersJS(或只需将 raw javascript code 复制并粘贴到 chrome 的控制台窗口)并为您感兴趣的元素指定事件类型和 jquery 选择器。
对于您的示例,您可以通过执行快速找到您提到的事件处理程序
findEventHandlers("click", "#el")
findEventHandlers("mouseover", "#el")
这是返回的内容:
element 注册事件处理程序的实际元素
events 包含我们感兴趣的事件类型的 jquery 事件处理程序信息的数组(例如单击、更改等) handler 实际的事件处理程序方法,您可以通过右键单击它并选择 Show function definition selector 为委托提供的选择器事件。对于直接事件,它将为空。包含此事件处理程序所针对的元素的列表。例如,对于在文档对象中注册并针对页面中所有按钮的委托事件处理程序,此属性将列出页面中的所有按钮。您可以将它们悬停并查看它们以 chrome 突出显示。
handler 实际的事件处理程序方法,您可以通过右键单击它并选择显示函数定义来查看
选择器 为委托事件提供的选择器。对于直接事件,它将为空。
包含此事件处理程序所针对的元素的列表。例如,对于在文档对象中注册并针对页面中所有按钮的委托事件处理程序,此属性将列出页面中的所有按钮。您可以将它们悬停并查看它们以 chrome 突出显示。
你可以试试here
为此,我使用 eventbug 插件来触发萤火虫。
我已经将@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 本身设置的事件。
要检查元素上的事件:
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])
getEvents
方法总体上很棒,但问题是,它在 IE11 中提供了重复的条目(我知道,IE 再次,但公司需要它......)。编辑:$._data 包含元素的重复事件,即使在 FF 上它不包含任何...奇怪的 IE 世界。但重要的是要注意这种重复事件的可能性。
从 1.9 开始,除了使用 Migrate 插件恢复旧行为之外,没有记录的方法来检索事件。您可以使用 jps 提到的 _.data() 方法,但这是一种内部方法。因此,如果您需要此功能,只需做正确的事并使用 Migrate 插件即可。
来自 .data("events")
上的 jQuery 文档
在 1.9 之前,如果没有其他代码定义了名为“events”的数据元素,则可以使用 .data("events") 为元素检索 jQuery 未记录的内部事件数据结构。这种特殊情况已在 1.9 中删除。没有公共接口来检索这个内部数据结构,并且它仍然没有记录。但是,jQuery Migrate 插件为依赖它的代码恢复了这种行为。
jQuery._data( elem, "events" );
...
我创建了一个自定义 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._data('ct100_ContentPlaceHolder1_lcsSection','events')["EVENT_NAME"].map(function(elem){return elem.handler;});
未捕获的类型错误:无法在 <anonymous>:1:62 读取未定义的属性“EVENT_NAME”
'ct100_ContentPlaceHolder1_lcsSection'
是字符串,而不是 DOM 元素。
可以使用以下方法检索事件:
jQuery(elem).data('events');
或 jQuery 1.8+:
jQuery._data(elem, 'events');
注意: 使用 $('selector').live('event', handler)
限定的事件可以使用以下方法检索:
jQuery(document).data('events')
jQuery 不允许您只是简单地访问给定元素的事件。您可以使用未记录的内部方法访问它们
$._data(element, "events")
但它仍然不会给你所有的事件,准确地说不会显示分配给你的事件
$([selector|element]).on()
这些事件存储在文档中,因此您可以通过浏览来获取它们
$._data(document, "events")
但这是一项艰苦的工作,因为整个网页都有活动。
上面的 Tom G 创建了一个函数,该函数仅过滤给定元素的事件并合并两种方法的输出,但它存在在输出中复制事件的缺陷(并且有效地在元素的 jQuery 内部事件列表上与您的应用程序混淆)。我修复了这个缺陷,你可以在下面找到代码。只需将其粘贴到您的开发控制台或您的应用程序代码中,并在需要时执行它以获得给定元素的所有事件的漂亮列表。
需要注意的是,元素实际上是 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>
该图像附加了一个单击事件处理程序:
imageNode.click(function () { ... });
我的意图是将可点击区域扩展到整行,所以我首先得到了所有图像和相关行:
tableNode.find("img.folder").each(function () {
var tr;
tr = $(this).closest("tr");
// <-- actual answer
});
现在在实际的 anwer 行中,我只是做了如下操作,给出了原始问题的答案:
tr.click(this.onclick);
所以我直接从 DOM 元素中获取事件处理程序,并将其放入 jQuery click 事件处理程序中。奇迹般有效。
现在,到一般情况。在旧的 jQuery 之前的日子里,你可以通过 Douglas 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;
}
}
});
}
如果您使用的是 chrome,请尝试 jquery 调试器插件: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"); // 示例事件处理程序 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 (事件,函数(i,事件){如果(!事件)返回;$.each(事件,函数(j,h){var found = false;如果(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); } }); }); });
$._data($(elem).get(0), "events")
var events = (jQuery._data || jQuery.data)(elem, 'events');