33

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

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

出于测试目的,我在复选框而不是标签上触发了单击事件,并且此处复选框单击事件仅按应有的方式触发一次。

这是小提琴。 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>

查询

$(document).ready(function () {

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


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

});
4

8 回答 8

45

永远不会调用of $('#test checkbox'),因为您没有带有 name 的标签checkbox

并且取决于您是否单击复选框或标签,回调$('#test label')被调用一次或两次导致冒泡,因为输入元素是标签的一部分并且是一个联合,因此如果标签是单击,也会收到事件(它是不冒泡,你做不到event.stopPropagation())。

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

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

点击标签:

标签
输入

点击输入:

输入

编辑 如果您只想处理单击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');
    }
});
于 2013-06-19T07:31:57.443 回答
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');
    });
});

小提琴

还喜欢使用$.on并注意:checkbox选择器的使用,或者[type="checkbox"]根据 JQuery API 更快和更兼容的选择器(属性选择器

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

于 2013-06-19T07:36:12.880 回答
3

OP 找到了一种解决方案来防止标签的单击事件处理程序在一次单击时执行两次。选择的答案也有很好的解决方案,但它错误地指出这与事件冒泡无关。

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

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


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

当输入不在标签内时,标签的“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');
    }
});
于 2015-06-12T18:54:09.747 回答
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 后刚刚添加了检查行为

于 2013-06-19T07:57:27.457 回答
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。

于 2014-03-12T18:17:31.860 回答
0

这主要发生在您为具有子元素 Y 的 X 元素触发“点击”以及用户点击 Y 时。

从实际单击的元素冒泡的事件是您不想要的不想要的事件。

您有两种选择来避免这种双重触发......

1) 使用 $('selector').triggerHandler('any_standard_event_name') - 这里的标准事件是指“单击”、“更改”、“悬停”等(我从未尝试过此选项)

2) 使用自定义事件名称。例如。$('selector').trigger('my.click');

在http://api.jquery.com/trigger/上阅读更多信息

于 2015-02-26T08:31:22.597 回答
0

关于我的情况以及我使用材料设计的 md 按钮的事实,上面的建议效果不佳,因为它大大减少了在我的 android 上接收手指按压的区域的足迹。更不用说我有时会得到超过 3 个标记名,而不是 2 个标记名(按钮、跨度或 MD-ICON)。此外,网络上其他地方更改我的 Aria 版本的建议也无济于事。我最终发现问题是我在 angular.js 之前加载了 jquery,即使 ng-infinate-scroll 的帮助文档说要先加载 jquery。无论如何,如果我在 angular ng-infinate-scroll 之后尝试加载 jquery 将停止工作。所以我下载了最新版本的 ng-infinate-scroll (non-stable) 1.2.0 版,现在我可以在 angular 之后加载我的 jquery。

于 2015-05-05T18:32:50.307 回答
0

我的元素也相互包裹。

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

.off{
   pointer-events:none;
}
于 2016-02-14T08:06:57.217 回答