如何检查click事件是否已绑定-JQuery


130

我将带有按钮的click事件绑定:

$('#myButton').bind('click',  onButtonClicked);

在一种情况下,这会被多次调用,所以当我执行一次操作时,trigger我看到了多个我想防止的ajax调用。

bind只有在未绑定之前,我该怎么办。


1
伙计,我认为+ Konrad Garus具有最安全的答案(stackoverflow.com/a/6930078/842768),请考虑更改您接受的答案。干杯! 更新:也请检查+ Herbert Peters的评论!那是最好的方法。
giovannipds

有关当前标准,请参见下面的@A Morel答案(stackoverflow.com/a/50097988/1163705)。更少的编码,使所有猜测工作,算法和/或从等式中搜索现有元素成为可能。
Xandor

Answers:


117

更新时间:2012 年8月24日:在jQuery 1.8中,不再可以使用来访问元素的事件.data('events')。(有关详细信息,请参见此bug。)可以使用jQuery._data(elem, 'events')内部数据结构访问相同的数据,该内部数据结构未记录,因此不能保证100%保持稳定。但是,这应该不成问题,并且上面插件代码的相关行可以更改为以下内容:

var data = jQuery._data(this[0], 'events')[type];

jQuery事件存储在名为的数据对象中events,因此您可以在其中进行搜索:

var button = $('#myButton');
if (-1 !== $.inArray(onButtonClicked, button.data('events').click)) {
    button.click(onButtonClicked);
}

当然,最好是可以构造应用程序,以使此代码仅被调用一次。


可以将其封装到插件中:

$.fn.isBound = function(type, fn) {
    var data = this.data('events')[type];

    if (data === undefined || data.length === 0) {
        return false;
    }

    return (-1 !== $.inArray(fn, data));
};

然后,您可以致电:

var button = $('#myButton');
if (!button.isBound('click', onButtonClicked)) {
    button.click(onButtonClicked);
}

10
+1以进行编辑。今天阅读这篇文章,我正在使用1.8。谢谢。
Gigi2m02 2012年

2
感谢您的编辑。这是仅用于按钮还是我也可以将其用于<a>?因为当我尝试它时,它说出jQuery._data()以下错误TypeError: a is undefined
Houman 2012年

我会将行包装var data = jQuery._data(this[0], 'events')[type];在try catch中,并在catch中返回false。如果没有事件绑定到this [0],则对[type]的调用将引起“无法获取未定义或空引用的属性'click'”的变化,并且显然这也告诉您您需要了解什么。
Robb Vandaveer 2014年

我不确定_data对象是否在jQuery 2.0.3中更改,但是我无法为此使用$ .inArray。您要比较的函数位于每个数据项的称为“处理程序”的属性中。我将其修改为使用简单的for语句并检查了字符串的等效性,我假设inArray会这样做。for (var i = 0; i < data.length; i++) { if (data[i].handler.toString() === fn.toString()) { return true; } }
Robb Vandaveer 2014年

为什么不将更新/编辑移至顶部?...这是实际的正确答案。
Don Cheadle

179

另一种方法-使用CSS类和过滤器标记此类按钮:

$('#myButton:not(.bound)').addClass('bound').bind('click',  onButtonClicked);

在最新的jQuery版本中,替换bindon

$('#myButton:not(.bound)').addClass('bound').on('click',  onButtonClicked);

4
优秀的!谢谢康拉德,这真是妙不可言。我喜欢这样优雅而简单的方法。我非常确定它的性能也更高,因为每个单个元素(已经附加了单击事件处理程序)都不必在某些大型事件存储桶中进行全面搜索,而将每个元素进行比较。在我的实现中,我将添加的帮助程序类命名为“ click-bound”,我认为这是一个更易于维护的选项:$(“。list-item:not(.click-bound)”)。addClass(“ click-bound”) ;
尼古拉斯·彼得森

1
正如公认的答案中所述:“当然,最好是可以构造应用程序,这样该代码仅被调用一次。” 这样就完成了。
杰夫·德格2014年

在我的情况下+1,关闭/打开以及绑定/取消绑定确实阻止了多次通话。这是有效的解决方案。
2014年

2
这是更好的性能解决方案,因为代码可以检查CSS类的存在和已存在的滑动绑定。其他解决方案将执行一个“先绑定后重新绑定”过程,并且开销更大(至少我可以告诉我)。
Phil Nicholas

1
2期。(在可绑定到多个元素的插件中使用时)将resize事件绑定到window对象时将不起作用。使用data('bound',1)代替addClass('bound')是另一种有效的方法。销毁事件时,它可能会这样做,而其他实例依赖它。因此,建议检查其他实例是否仍在使用中。
赫伯特·彼得斯2015年

59

如果使用jQuery 1.7+:

您可以offon以下时间致电:

$('#myButton').off('click', onButtonClicked) // remove handler
              .on('click', onButtonClicked); // add handler

如果不:

您可以解除绑定第一个事件:

$('#myButton').unbind('click', onButtonClicked) //remove handler
              .bind('click', onButtonClicked);  //add handler

1
这并不是一个很好的解决方案,但只需取消绑定一个处理程序即可改进它.unbind('click', onButtonClicked)请参阅手册
lonesomeday

16
您实际上可以在添加处理程序时为其命名空间,然后解除绑定变得非常简单。$(sel).unbind("click.myNamespace");
马克

@lonesomeday是您的示例使用“ unbind”来表示任何不同吗?.unbind实际上与.off并不相同,所以您不得不写$('#myButton').unbind('click', onButtonClicked).bind('click', onButtonClicked);
Jim

1
@Jim您会在我发表评论的三年后看到问题已被编辑!(以及在我发表评论后的几分钟内。我评论的内容不再存在,这就是为什么它似乎似乎没有太大意义的原因。)
lonesomeday

@lonesomeday hmmm我不确定为什么要编辑它,您认为我应该回滚吗?
Naftali又名Neal

8

我认为最好的方法是使用live()或委托()在父级而不是每个子级元素中捕获事件。

如果您的按钮位于#parent元素内,则可以替换:

$('#myButton').bind('click', onButtonClicked);

通过

$('#parent').delegate('#myButton', 'click', onButtonClicked);

即使执行此代码时#myButton尚不存在。


2
不推荐使用的方法
Dobs

8

我写了一个很小的插件,叫做“ once”。断断续续地执行in元素。

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

并简单地:

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

9
.one()将在第一次执行后删除处理程序。
Rodolfo Jorge Nemer Nogueira 2015年

3
这里“一次”是一次附加一个处理程序。jQuery中的“一个”用于运行一次而不附加一次。
Shishir Arora

1
我知道事实之后我会加入,但是不off删除给定类型的所有处理程序吗?意思是如果有一个单独的单击处理程序不相关但在同一项目上,那也不会被删除吗?
Xandor

只需在事件上使用名称空间,这样它就不会删除所有处理程序,例如:'keypup.test123'–
SemanticZen


3

这是我的版本:

Utils.eventBoundToFunction = function (element, eventType, fCallback) {
    if (!element || !element.data('events') || !element.data('events')[eventType] || !fCallback) {
        return false;
    }

    for (runner in element.data('events')[eventType]) {
        if (element.data('events')[eventType][runner].handler == fCallback) {
            return true;
        }

    }

    return false;
};

用法:

Utils.eventBoundToFunction(okButton, 'click', handleOkButtonFunction)

2

基于@ konrad-garus的答案,但是使用data,因为我相信class应该主要用于样式设计。

if (!el.data("bound")) {
  el.data("bound", true);
  el.on("event", function(e) { ... });
}

2

为了避免检查/绑定/解除绑定,您可以更改方法!为什么不使用Jquery .on()?

由于不建议使用jQuery 1.7,.live()和.delegate(),因此现在可以使用.on()来

现在和将来与当前选择器匹配的所有元素附加事件处理程序

这意味着您可以将事件附加到仍然存在的父元素,并附加子元素,无论它们是否存在!

当您像这样使用.on()时:

$('#Parent').on('click', '#myButton'  onButtonClicked);

您在父项上单击事件单击,并搜索子项“ #myButton”(如果存在)...

因此,当您删除或添加子元素时,不必担心是否要添加或删除事件绑定。


对于当前的标准,这绝对是最好的答案。我认为在父级上设置处理程序以监视孩子的功能并没有广为人知,但是这是一个相当优雅的解决方案。我多次触发事件,每次触发的总次数不断增加。这行代码完成了整个技巧,如果不使用.off它,我相信会删除流程中无关的处理程序。
Xandor

1

尝试:

if (typeof($("#myButton").click) != "function") 
{
   $("#myButton").click(onButtonClicked);
}

0
if ($("#btn").data('events') != undefined && $("#btn").data('events').click != undefined) {
    //do nothing as the click event is already there
} else {
    $("#btn").click(function (e) {
        alert('test');
    });
}

0

截至2019年6月,我已经更新了该功能(并且该功能可以满足我的需要)

$.fn.isBound = function (type) {
    var data = $._data($(this)[0], 'events');

    if (data[type] === undefined || data.length === 0) {
        return false;
    }
    return true;
};

-2

jQuery有解决方案

$( "#foo" ).one( "click", function() {
  alert( "This will be displayed only once." );
}); 

当量:

$( "#foo" ).on( "click", function( event ) {
  alert( "This will be displayed only once." );
  $( this ).off( event );
});

1
您的答案与问题无关。问题是只将功能绑定到元素的事件一次。
米哈尔扎莱夫斯基
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.