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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17185265/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-26 18:36:14  来源:igfitidea点击:

Jquery click event triggers twice when clicked on html label

jqueryeventsclick

提问by sravis

I have an div container which contains html checkbox and its label. Using jquery i wanted to trigger an click event when someone clicks on label in this container.

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

I see that jquery click event triggers twice when i click on label!

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

For testing purpose i triggered click event on checkbox instead of label and here checkbox click event triggers only once as it should be.

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

Here is the fiddle. http://jsfiddle.net/AnNvJ/2/

这是小提琴。 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');
    });

});

回答by t.niese

The one of $('#test checkbox')is never called, because you don't have a tag with name checkbox.

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

And depending if you click on checkbox or the label, the callback for $('#test label')is called once or twice cause of the bubblingbecause the input element is part of the label and is one unionand therefore also received the event if the label is click (it is not bubbling, you can't do event.stopPropagation()).

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

You can check this if you change your code this way:

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

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

Click on label:

点击标签:

LABEL
INPUT

标签
输入

Click on input:

点击输入:

INPUT

输入

EDITIf you only want to handle the click on the labeland not the checkbox - and you can't change your HTML structure - you can just ignorethe event of the inputelement.

编辑如果你只想处理点击label而不是复选框 - 并且你不能改变你的 HTML 结构 - 你可以忽略input元素的事件。

Either this way:

无论是这样:

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

Or using jQuery to test:

或者使用jQuery来测试:

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

回答by TecHunter

It's because you put the input inside the label so when you click the checkbox you also click every parents (that's called bubbling)EDIT, credit to @t.niese : in fact there is no bubbling here because the issue is when you click on label and it only bubbles up.

这是因为您将输入放在标签内,因此当您单击复选框时,您还会单击每个父级(称为冒泡)编辑,归功于 @t.niese:实际上这里没有冒泡,因为问题是当您单击标签时它只会冒泡。

To prevent double click event but also check the checkbox you can use :

要防止双击事件,还要检查您可以使用的复选框:

$(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

小提琴

Also prefer the usage of $.onand note the usage of :checkboxselectoror [type="checkbox"]which according to JQuery API is faster and more compatible (attribute selectors)

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

event.preventDefault()will stop every action handled by browser for the native tag event.stopPropagation()prevents bubbling and any parent handlers from being notified of the event

event.preventDefault()将停止浏览器为原生标签处理的每个动作, event.stopPropagation()防止冒泡,并且任何父处理程序都不会收到该事件的通知

回答by John S

The OP found one solution to prevent the click event handler for the label from getting executed twice for a single click. The selected answer also has a good solution, but it incorrectly states that this has nothing to do with event bubbling.

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

The reason there are two clicks does have to do with event bubbling.

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

Clicking on a label that is associated with an input causes two click events to be triggered. The first click event is triggered for the label. The default handling of that click event causes a second click event to get triggered for the associated input. If the input is a descendent of the label, the second click event bubbles up to the label. That is why the click event handler for the label is called twice.

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



Therefore one way to solve this problem (as the OP discovered) is to not place the input inside the label element. There will still be two click events, but the second click event will not bubble up from the input to the label.

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

When the input is not inside the label, the label's "for" attribute can be used to associate the label with the input. The "for" attribute must be set to the "id" value of the input.

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

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


Another solution would be to stop the event from bubbling up from the input:

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

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

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


Then there's the solution presented in the selected answer, which is to have the label's click handler ignore the event when it bubbles up from the input. I prefer to write it like this though:

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

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

回答by Chococroc

You MUST use preventDefault in your label and stopPropagation in your checkbox:

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

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

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

The Code:

编码:

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

In this way you avoid the behaviour @t.niese explains

通过这种方式,您可以避免@t.niese 解释的行为

Thank you to the previous answers, I wouldn't figure out without them, :D.

感谢您之前的答案,如果没有它们,我将无法弄清楚,:D。

Update

更新

As t.niese points up, here is the answer I've updated with the behaviour:

正如 t.niese 指出的那样,这是我用行为更新的答案:

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

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

Just added the check behaviour after using the preventDefault XD

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

回答by Will Hitchcock

I just ran into this same issue where clicking on the label was triggering two separate click events. I was able to solve the problem for myself by adding a nameattribute to the input and a forattribute to the label.

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

For example:

例如:

<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>

No JavaScript needed.

不需要 JavaScript。

回答by EGL 2-101

This happens mostly when you trigger 'click' for X element having child element Y and when user clicks on Y.

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

The event bubbled from actually clicked element is undesired event that you don't want.

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

You have two options to avoid this double triggering...

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

1) Use $('selector').triggerHandler('any_standard_event_name') - Here by standard event I mean 'click', 'change', 'hover' etc. (I have never tried this option)

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

2) Use custom event name. eg. $('selector').trigger('my.click');

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

Read more on http://api.jquery.com/trigger/

http://api.jquery.com/trigger/上阅读更多内容

回答by Helzgate

Regarding my case and the fact that I'm using material design's md-button the suggestions above didn't work very well because it dramatically reduced the footprint of the area receiving finger press on my android. Not to mention instead of just 2 tagNames I would get upwards of 3 sometimes (BUTTON, SPAN, or MD-ICON). Also the suggestion elsewhere on the web to change my version of Aria didn't help either. I ended up finding the problem was that I was loading jquery before angular.js even though ng-infinate-scroll's help doc says to load jquery first. Anyway, if I tried to load jquery after angular ng-infinate-scroll would quit working. So I downloaded the latest version of ng-infinate-scroll (non-stable) version 1.2.0 and now I can load my jquery after angular.js and my infinite scroll works all the issues I had with ng-click firing multiple times is gone.

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

回答by ivahidmontazer

My elements wrapped one another, also.

我的元素也相互包裹。

So i used a simple CSS trick for this solution :

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

.off{
   pointer-events:none;
}