测试jQuery中元素是否绑定了事件处理程序

194

使用jQuery,能否确定元素是否具有点击处理程序、更改处理程序或任何类型的事件处理程序?

此外,能否确定给定类型事件的点击处理程序(或其他类型的事件处理程序)的数量以及事件处理程序中包含的函数有哪些?

11个回答

141
您可以从数据缓存中获取此信息。
例如,将它们记录到控制台(firebug、ie8):
console.dir( $('#someElementId').data('events') );
或者遍历它们:
jQuery.each($('#someElementId').data('events'), function(i, event){

    jQuery.each(event, function(i, handler){

        console.log( handler.toString() );

    });

});

另一种方法是您可以使用以下书签工具,但显然这不能在运行时帮助。


7
是的 Russ,那是真的。但行内处理程序很糟糕,不值得展示! - redsquare
78
注意:在jQuery 1.8中已经移除了$(element).data('events')。对于“调试”,你可以使用$._data(element, 'events'),但它是未经记录的(并且可能会更改)。http://blog.jquery.com/2012/08/09/jquery-1-8-released/ - gen_Eric
2
@gotqn 你希望每个人都更新他们的答案来跟进新的 API 吗?请注意回答的日期... - redsquare
4
当然我已经预料到了。你可以查看数百个受欢迎的答案,这些答案一直在不断更新。 - gotqn
2
$._data($("#element")[0]).events - jtromans
显示剩余16条评论

133

当绑定还不存在时将其删除并不是最好的解决方案,但似乎足够有效!第二次“点击”时,您可以确信它不会创建重复的绑定。

因此,我使用die()或unbind()来实现:

$("#someid").die("click").live("click",function(){...

或者

$("#someid").unbind("click").bind("click",function(){...

或者在最近的jQuery版本中:

$("#someid").off("click").on("click",function(){...

7
+1 非常整洁,尽管它没有回答问题。 - Zephyr was a Friend of Mine
7
对于 jQuery 1.7 及更高版本,请使用 .off("click") 替代 .die() 或者 .unbind() - David Clarke
这只是一个临时解决方案。最好找出代码为什么会执行两次并修复该错误,或者找出其他地方绑定被调用的位置并防止它发生。 - mattalxndr
必须同意@mattalxndr的观点。在这种情况下,至少要使用命名空间来避免禁用由不相关代码绑定的事件,例如:$(“#someid”).die(“click.myPlugin”).live(“click.myPlugin”,function(){... - Claus Conrad
2
我想补充一点,如果您需要附加一个仅运行一次然后自动删除的事件,请使用one()方法。$("body").one("click",function(){ alert('test');}); - Daniel Katz
显示剩余2条评论

35

2
这个插件应该成为任何使用jQuery的人的首选答案。 - apiguy
希望我能为其他人节省一些时间。hasEventListener 对于 live 绑定的事件不起作用。(v1.0.5) - SooDesuNe
1
我的hasEventListener插件将在本周更新,现在已经完全支持实时和委托事件。 - Sebastien P.
2
为什么这部分功能不是jQuery原生的!!! 干得好 +1 - crush
5
有没有可能提供一个1.9兼容的版本? - zeroasterisk

19

自jQuery 1.8开始,此解决方案不再受支持,如我们可以在此处的博客中阅读:

$(element).data("events"):此功能在1.8中已删除, 但您仍可以通过$._data(element, "events")访问事件数据进行调试。 请注意,这不是受支持的公共接口;实际数据结构可能会从版本到版本发生不兼容的更改。

因此,您应该解除绑定/重新绑定它,或者简单地使用布尔值来确定您的事件是否已附加(在我看来这是最好的解决方案)。


为什么它被删除了,有任何指定的原因吗? - pilau
因为jQuery使用(.data)来存储其内部事件逻辑。 - adriendenat
1
$._data 现在是做什么用的? - pilau
1
我刚刚找到了这个,它解释了一切 :) - pilau
你会在哪里设置布尔值? - Noumenon

16

我认为这可能是使用jQuery 1.9.*更新过的。

目前我发现这是唯一对我有效的东西:

$._data($("#yourElementID")[0]).events

10

适用于 jQuery 1.9+

var eventListeners = $._data($('.classname')[0], "events");

我需要使用 [0] 数组字面量。


10

我写了一个非常小的插件叫做"once",它可以做到这一点:

$.fn.once = function(a, b) {
    return this.each(function() {
        $(this).off(a).on(a,b);
    });
};

并且简单地:

$(element).once('click', function(){
});

1
@Luke 我知道这已经过时了,但你是错的。据我所知,这与jQuery.one()不同,因为它允许事件在自我删除之前仅运行(触发)一次。这个.once()函数只是确保在绑定替换程序之前删除任何现有处理程序(然后可以多次触发)。也许函数名称是令人困惑的部分,或者更好地考虑为$.fn.replaceOn()? - Jon Bellamy

5

我认为提到的hasEventListener插件无法处理自定义事件,例如:

var obj = {id:'test'};
$(obj).bind('custom', function(){
    alert('custom');
}).trigger('custom');

alert($(obj).hasEventListener('custom'));

此外,在jQuery 1.5中,如果您使用$(target).data('events'),请注意需要小心,因为它对于已绑定到对象的事件返回值不同。

您需要执行以下操作:

var events = $(target).data("events");
if(typeof events === "function"){
   events = events.events;
}

我正在使用这种方法,它可以运行,但感觉有点像我在受jQuery内部的支配,而我真的不应该这样做!


2

我有同样的需求,很快就修补了现有代码,使其能够像这样做:

 if( $('.scroll').hasHandlers('mouseout') )  // could be click, or '*'...
 { 
   ... code ..
 }

它也适用于事件委托:
 if ( $('#main').hasHandlers('click','.simple-search') )  ...

It is available here : jquery-handler-toolkit.js


1

参考SJG的回答W3Schools.com,

从jQuery 1.7版本开始,off()方法是unbind()、die()和undelegate()方法的新替代品。这个方法为API带来了很多一致性,我们建议您使用这个方法,因为它简化了jQuery代码库。

这样做:

$("#someid").off("click").live("click",function(){...

或者

$("#someid").off("click").bind("click",function(){...

2
bind方法现在已经被弃用,所以最好使用$("#someid").off("click").on("click",function(){...} - Zoltán Süle

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接