单击html标签时,Jquery单击事件触发两次

时间:2013-06-19 07:27:48

标签: jquery events click

我有一个div容器,其中包含html复选框及其标签。 使用jquery我想在有人点击此容器中的标签时触发点击事件。

当我点击标签时,我看到jquery点击事件触发了两次!

出于测试目的,我在复选框上触发了click事件而不是标签 在这里,复选框只点击事件触发器一次。

这是小提琴。 http://jsfiddle.net/AnNvJ/2/

<tr>
    <td>
        <div id="test">
            <label>
                <input type="checkbox" id="1" />demo1</label>
            <label>
                <input type="checkbox" id="2" />demo2</label>
            <label>
                <input type="checkbox" id="3" />demo3</label>
        </div>
    </td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
</tr>

JQUERY

$(document).ready(function () {

    $('#test label').live('click', function (event) {
        alert('clicked');
    });


    $('#test checkbox').live('click', function (event) {
        alert('clicked');
    });

});

8 个答案:

答案 0 :(得分:40)

永远不会调用$('#test checkbox')之一,因为您没有名称为checkbox的标记。

依赖于复选框或标签,$('#test label')的回调被调用一次或两次冒泡的原因因为输入元素是标签的一部分而且是一个 union 因此如果标签被点击也会收到该事件(它不是冒泡,你不能event.stopPropagation())。

如果您以这种方式更改代码,可以检查:

 $('#test label').live('click', function (event) {
        event.stopPropagation(); //<-- has no effect to the described behavior
        console.log(event.target.tagName);
 });

点击标签:

  

LABEL
    INPUT

点击输入:

  

INPUT

修改 如果您只想处理label上的点击而不是复选框 - 而且您无法更改HTML结构 - 您只能忽略 input的事件元件。

要么这样:

$('#test label').live('click', function (event) {
    if( event.target.tagName === "LABEL" ) {
         alert('clicked');
    }
});

或使用jQuery进行测试:

$('#test label').live('click', function (event) {
    if( $(event.target).is("label") ) {
         alert('clicked');
    }
});

答案 1 :(得分:9)

这是因为你把输入放在标签内,所以当你点击复选框时你也点击每个父母(那叫做冒泡)编辑,归功于@ t.niese:实际上没有冒泡这里是因为问题是当你点击标签时它只会起泡。

要防止双击事件,请同时选中您可以使用的复选框:

$(document).ready(function () {

    $('#test label').on('click', function (event) {
        event.preventDefault();
        var $check = $(':checkbox', this);
        $check.prop('checked', !$check.prop('checked'));
        alert('clicked label');
    });


    $('#test :checkbox').on('click', function (event) {
        event.stopPropagation();
        alert('clicked checkbox');
    });
});

FIDDLE

也更喜欢$.on的使用,并注意根据JQuery API的:checkbox selector[type="checkbox"]的使用更快且更兼容(attribute selectors

event.preventDefault()将停止浏览器为本机标记处理的每个操作 event.stopPropagation()阻止冒泡和任何父处理程序被通知事件

答案 2 :(得分:3)

OP发现了一个解决方案,可以防止标签的click事件处理程序单次执行两次。所选答案也有一个很好的解决方案,但它错误地指出这与事件冒泡无关。

有两次点击的原因与事件冒泡有关。

单击与输入关联的标签会导致触发两个单击事件。为标签触发第一次单击事件。该click事件的默认处理导致为相关输入触发第二次单击事件。如果输入是标签的后代,则第二次单击事件会冒泡到标签。这就是为什么标签的click事件处理程序被调用两次。

因此解决此问题的一种方法(如发现的OP)是不将输入放在label元素中。仍然会有两个点击事件,但第二个点击事件不会从输入到标签冒泡。

当输入不在标签内时,标签的“for”属性可用于将标签与输入相关联。必须将“for”属性设置为输入的“id”值。

<input type="checkbox" id="1" />
<label for="1">demo1</label>

另一个解决方案是阻止事件从输入中冒出来:

$('#test :checkbox').on('click', function(event) {
    event.stopPropagation();
});

$('#test label').on('click', function() {
    alert('clicked');
});

然后在所选答案中显示解决方案,即让标签的点击处理程序在输入中冒泡时忽略该事件。我喜欢这样写:

$('#test label').on('click', function(event) {
    if (event.target == this) {
        alert('clicked');
    }
});

答案 3 :(得分:1)

您必须在标签中使用preventDefault并在复选框中使用stopPropagation:

http://jsfiddle.net/uUZyn/5/

守则:

$(document).ready(function () {

    $('#test label').on('click', function (event) {
      event.preventDefault();        
      alert('clicked label');
      var ele = $(this).find('input');
    if(ele.is(':checked')){
      ele.prop('checked', false);        
    }else{
      ele.prop('checked', true);
    }
  });

  $('#test :checkbox').on('click', function (event) {
    event.stopPropagation();
    alert('clicked checkbox');
  });
});

这样就可以避免@ t.niese解释

的行为

感谢您之前的回答,如果没有他们,我不会想到:D。

更新

当t.niese指出时,这是我用行为更新的答案:

http://jsfiddle.net/uUZyn/6/

使用preventDefault后添加了检查行为 XD

答案 4 :(得分:0)

我遇到了同样的问题,点击标签时触发了两个单独的点击事件。我能够通过在输入中添加name属性并为标签添加for属性来为自己解决问题。

例如:

<div id="test">
    <label for="checkbox1">
        <input type="checkbox" name="checkbox1" id="1" />demo1</label>
    <label for="checkbox2">
        <input type="checkbox" name="checkbox2" id="2" />demo2</label>
    <label for="checkbox3">
        <input type="checkbox" name="checkbox3" id="3" />demo3</label>
 </div>

不需要JavaScript。

答案 5 :(得分:0)

当你为具有子元素Y的X元素触发'click'并且当用户点击Y时,会发生这种情况。

从实际点击的元素冒出的事件是您不想要的不受欢迎的事件。

您有两种方法可以避免这种双重触发......

1)使用$('selector')。triggerHandler('any_standard_event_name') - 这里的标准事件我指的是'click','change','hover'等等(我从未尝试过这个选项)

2)使用自定义事件名称。例如。 $( '选择')触发( 'my.click');

详细了解http://api.jquery.com/trigger/

答案 6 :(得分:0)

关于我的情况以及我使用材料设计的md按钮的事实,上面的建议并没有很好地发挥作用,因为它大大减少了接受手指按压的区域的占地面积机器人。更不用说只有2个tagNames,我有时会得到3个(BUTTON,SPAN或MD-ICON)。另外,网上其他地方改变我的Aria版本的建议也没有帮助。我最终发现问题是我在angular.js之前加载jquery,即使ng-infinate-scroll的帮助文档说首先加载jquery。无论如何,如果我尝试在角度ng-infinate-scroll之后加载jquery将退出工作。所以我下载了最新版本的ng-infinate-scroll(非稳定)版本1.2.0,现在我可以在angular.js之后加载我的jquery,我的无限滚动工作了我用ng-click多次激活的所有问题是走了。

答案 7 :(得分:0)

我的元素也相互包裹着。

所以我在这个解决方案中使用了一个简单的CSS技巧:

.off{
   pointer-events:none;
}