JavaScript 今天发现一个有趣的事件绑定陷阱

huacnlee · 2012年02月20日 · 最后由 sigma 回复于 2013年11月05日 · 11510 次阅读
<a id="link_foo">Foo</a><a id="link_foo">Foo</a>
<script type="text/javascript">
function bindFooClick(){
  $("#link_foo").click(function(){
    console.log "asd"
  });
}
bindFooClick();
bindFooClick();
bindFooClick();
bindFooClick();
</script>

然后去点击 Foo 这个连接,将会出现 4 个日志输出。

如果不小心这个事件绑定被搞得成倍增长了,那就等着暴掉吧。

所以需要在 bindFooClick 绑定事件前去掉之前的绑定

function bindFooClick(){
  $("#link_foo").unbind("click");
  $("#link_foo").bind("click", function(){
    console.log "asd"
  });
}

不知道 jQuery 有没有自带类似防止重复绑定事件的函数。

没遇到过类似的情况,不过刚才翻了一下 jquery,有这么一段——

jQuery.each(["bind", "one"], function( i, name ) {
......
        if ( name === "one" ) {
            handler = function( event ) {
                jQuery( this ).unbind( event, handler );
                return fn.apply( this, arguments );
            };
            handler.guid = fn.guid || jQuery.guid++;
        } else {
            handler = fn;
        }
......

所以你可以试试用 one 代替 bind,good luck :-)

我也试过了 one,似乎不行的

@huacnlee 这个问题是由于 jQuery 重复绑定事件导致的。bind() 在向里添加绑定,而不检查是否相同. 不要重复执行绑定操作,但如果是无法改掉,可以使用 $().unbind().bind() 来处理比较方便. 至于 @fwword 说的 $.one 是只触发一次后被清除,应该不满足此需求. 推荐看看http://www.w3school.com.cn/jquery/jquery_ref_events.asp 这个 jQuery 的事件列表。

还有一个类似的函数,die() 与 live() 在 jQuery 中叫委托事件,是说新生成的节点仍然可以触发此消息。

@huacnlee JavaScript 本身不带重复的 event callback 检测,这部分逻辑 jQuery 也不应该自带,你这里绑定的是一个匿名的 function,交给 jQuery 或者 JS 本身来防止重复 binding 就不合理了,应该是你的 App 自己来 handle 这类 binding。

这里有个项目是我刚刚 Google 到的,看看能不能配合你的 App 一起来防止对同一个 Dom element 重复绑定同样的 event callback。 https://github.com/sebastien-p/jquery.hasEventListener

不过对我来说这个需求基本不存在,自从 jQuery 完善了它的 live()delegate() 之后,我全部通过 delegate 来完成所有的 event handler,效率高且便于维护。

jq 1.7 里面已经增加 on 和 off 来统一事件绑定函数了,live 和 delegate 应该慢慢被弃用了

#5 楼 @edokeh 谢谢,jQ 的发展真迅猛,顺便找到一篇文章解释的非常详细关于用 on 和 off 替换调 live, delegate, bind 等方法。 http://www.andismith.com/blog/2011/11/on-and-off/

以后我也改用 live 方法了

#8 楼 @huacnlee = =b

jQuery’s .live() has been deprecated as of version 1.7.

#4 楼 @lgn21st 不是没这个问题,还是把问题留给开发者了,比如你 on/live/delegate 多次还是会有这个问题

#10 楼 @yedingding 恩,我本意是这个问题就是留给开发者的。

我用 jquery 的 facebox 插件时遇到 bind 重复绑定的问题

应该尽量避免这种逻辑。

handler 监听事件不要匿名,在绑定前先解绑:

$( ELEM ).unbind( 'click', handler_name ).bind( 'click', handler_name );

最近又了解了一种写法:

$( ELEM ).unbind( 'click.biz' ).bind( 'click.biz', function(){  });//事件也有命名空间
需要 登录 后方可回复, 如果你还没有账号请 注册新账号