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

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

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

出于测试目的,我在复选框上触发了click事件而不是标签,此处复选框单击事件触发器只应该一次。

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

  
   

JQUERY

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

$('#test checkbox')永远不会被调用,因为你没有带名字的标签checkbox

并且,如果您单击复选框或标签, $('#test label')的回调将被调用一次或两次冒泡,因为input元素是标签的一部分并且是一个联合 ,因此也接收了事件如果标签是点击(它不是冒泡,你不能做event.stopPropagation() )。

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

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

点击标签:

标签
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'); } }); 

这是因为你把输入放在标签内,所以当你点击复选框时你也点击每个父母(称为冒泡) EDIT,归功于@ 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 selector或[type="checkbox"]根据JQuery API更快更兼容( 属性选择器 )

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

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

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

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


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

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

   

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

 $('#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'); } }); 

您必须在标签中使用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后添加了检查行为

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

例如:

 

不需要JavaScript。

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

从实际点击的元素冒出的事件是您不想要的非期望事件。

你有两个选择来避免这种双重触发……

1)使用$(’selector’)。triggerHandler(’any_standard_event_name’) – 这里的标准事件我的意思是’点击’,’改变’,’hover’等等(我从未尝试过这个选项)

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

有关更多信息,请访问http://api.jquery.com/trigger/

关于我的情况和我使用材料设计的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多次触发的所有问题是不见了。

我的元素也相互包裹着。

所以我使用了一个简单的CSS技巧来解决这个问题:

 .off{ pointer-events:none; }