点击事件触发两次

5
我尝试在单击标签文本时运行某些函数,但是单击事件触发了两次。
HTML
<label class="label_one">
    Label One
    <input type="checkbox"/>
</label>

但如果我像这样更改HTML代码,它将不会发生。
<label for="test" class="label_two">
    Label Two
    <input type="checkbox"/>
</label>

我的脚本是这样的:

$('.label_one').click(function(){
    console.log('testing');
});

有人能解释一下为什么会出现这种情况吗?
我的jsfiddle在这里,请检查一下。
https://jsfiddle.net/sureshpattu/hvv6ucu8/3/


1
不知道为什么,但如果在第一个标签中添加for="text",它只会触发一次。 - Danmoreng
1
无法在 Chrome 中重现该问题。 - T J
第二个不会在单击标签时选中复选框,因为它的“for”属性是“text”。 - Hacketo
期望的行为是什么?单击标签时触发点击事件还是在复选框被点击时也触发(即两者都触发)?如果只有标签,您可以使用例如:if(e.target != this) return; 进行过滤。 https://jsfiddle.net/hvv6ucu8/6/ - A. Wolff
仅在标签点击时触发,@A.Wolff。 - Suresh Pattu
@SureshPattu 所以在输入点击事件中使用 if(e.target != this) return; 或设置 e.stopPropagation(); - A. Wolff
5个回答

5

这是因为事件冒泡的缘故。

一般来说,所有元素都会将事件冒泡到文档的根节点,而label标签会将事件冒泡到其子节点,这就是当你点击label dom时input标签被选中的原因。

所以在你的情况下,你将事件处理程序附加到了label标签上,因此:

  1. 当label标签被点击时,它调用事件处理程序
  2. 事件在其中传播并选择复选框,复选框将事件冒泡到其父节点,即label标签,因此它被调用两次。

要解决这个问题,只需将事件处理程序附加到输入/复选框标签上,它应该能正常工作。


1
一个事件不会冒泡到它的子元素 - A. Wolff
@A.Wolff 我找不到官方文档,但我会继续尝试。也许这不是纯粹的冒泡,但我可以证明事件对象正在传递给输入标签。https://jsfiddle.net/hvv6ucu8/7/ 请查看此代码片段。您可以取消注释警报语句以获取更多信息。一旦我找到官方资源,我将根据规范/文档更新我的答案并进行更正。 - rajuGT
实际上我的意思是,事件不会冒泡到复选框,但如果单击包装它的标签,则会在其上触发合成点击。例如,在单击复选框标签检查复选框的平台上,在下面的代码片段中单击标签可能会触发用户代理运行合成点击激活步骤的输入元素,就好像元素本身已被用户触发一样。然后,一旦合成点击事件完成,此事件将冒泡到其父级,也就是标签。 - A. Wolff
1
所以,实际上你的回答并没有错,但这种行为的主要原因是浏览器对“标记控件”行为的处理。事件总是从后代元素向上级元素冒泡/传播。捕获阶段则相反。 - A. Wolff

3

我在使用的Chrome版本中无法重现此问题。

但是如果您在某些浏览器中遇到这个问题,很可能是因为 -

根据规范,包含输入的标签以及通过for属性连接到输入的标签会在单击时触发与其关联的输入的单击事件。

因此,在您的第一种情况下,有2个单击事件:

  • <label>上的实际单击
  • 由标签触发的<input>上的单击

<input>上触发的一个将冒泡到<label>并触发您的处理程序。

在第二种情况下,由于指定了for属性并且没有匹配的id为“test”的输入,即使输入位于标签内,也不会触发额外的单击。


1
我无法在我正在使用的 Chrome 版本中重现这个问题。你是在测试哪个版本/操作系统?因为所有的 Chrome 版本都应该遵循有关此行为的规范。 - A. Wolff
@A.Wolff Chrome 46~适用于Windows,我尝试了他分享的fiddle,但是点击两个输入框只会添加一个日志记录。 - T J
在Win7上使用相同的Chrome和Here,预期的行为(问题)被触发了。也许与您的操作系统有关,但我会非常惊讶。也许那是个bug :) - A. Wolff

2
点击复选框时也会点击标签。尝试在输入上使用`.change`事件。
$('.label_one input').change(function(){
    var html = '<div class="log_sec_one">Log</div>';
    $('.logs').append(html);
});

$('.label_two input').change(function(){
    var html = '<div class="log_sec_two">Log</div>';
    $('.logs').append(html);
});

This text is a HTML code that includes a link to a website. The link text is "DEMO". In Chinese, it would be translated as:

演示


我想这确实是更容易的修复方法。 - A. Wolff

0
将您的输入移动到标签外部,并使用for = ""属性。
<label class="label_one" for="checkbox_one">
    Label One
</label>
<input type="checkbox" id="checkbox_one" />
<br/><br/>
<label for="checkbox_two" class="label_two">
    Label Two
</label>
<input type="checkbox" id="checkbox_two"/>

<div class="logs"></div>

JSFiddle: https://jsfiddle.net/hvv6ucu8/2/

JSFiddle:https://jsfiddle.net/hvv6ucu8/2/

0
<label for="text" class="label_one">
    Label One
    <input type="checkbox"/>
</label>
<br/><br/>
<label for="text" class="label_two">
    Label Two
    <input type="checkbox" name="1"/>
</label>

你忘记在标签(label_one)中添加for属性了。只需要更改一下就可以了。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接