单击标签时,jQuery Click触发两次


114

我正在使用jQuery创建自定义单选按钮,但我遇到了问题。当单击与收音机相关的标签时,单击事件会触发两次,如果我仅单击收音机本身,则效果很好(实际上,不是我要单击的收音机,而是包装整个输入和标签的div)。这是代码:

HTML:

 <div id="box">
     <asp:RadioButtonList ID="RadioButtonList1" runat="server">
         <asp:ListItem>RADIO1</asp:ListItem>
         <asp:ListItem>RADIO2</asp:ListItem>
         <asp:ListItem>RADIO3</asp:ListItem>
     </asp:RadioButtonList>
</div>

jQuery的:

<script type="text/javascript">
       $(function () {
            $('#box').find('input:radio').each(function (i) {

            var input = $(this);
            // get the associated label using the input's id
            var label = $('label[for=' + input.attr('id') + ']');
            // wrap the input + label in a div
            $('<div class="custom-radio"></div>').insertBefore(input).append(label, input);

            var wrapperDiv = input.parent();

            // find all inputs in this set using the shared name attribute
            var allInputs = $('input[name=' + input.attr('name') + ']');

            // necessary for browsers that don't support the :hover pseudo class on labels
            label.hover(

            function () {
                $(this).addClass('hover');
            }, function () {
                $(this).removeClass('hover checkedHover');
            });

            //bind custom event, trigger it, bind click,focus,blur events
            wrapperDiv.bind('updateState', function () {
                if ($(this)[0].children[1].checked) {
                    allInputs.each(function () {
                        var curDiv = $('div > label[for=' + $(this).attr('id') + ']').parent();
                        curDiv.removeClass('custom-radio-checked');
                        curDiv.addClass('custom-radio');
                    });
                    $(this).toggleClass('custom-radio custom-radio-checked');
                }
                else {
                    $(this).removeClass('custom-radio-checked checkedHover checkedFocus');
                }

            })
            .trigger('updateState')
            .click(function () { console.log('click'); })
            .focus(function () {
                label.addClass('focus');
            }).blur(function () {
                label.removeClass('focus checkedFocus');
            });
        }); 
       });
   </script>

对此行为有什么解决方案吗?

Answers:


130

尝试添加:

evt.stopPropagation();
evt.preventDefault();

到.bind()或.click()中的任意一个。另外,将参数添加evt到函数中,例如function(evt) {...


9
为什么会这样?
chovy

8
因为有嵌套项目。层次结构中的每个项目都会使事件冒泡。
约旦

7
如果您将其用于复选框,我也需要使用它来实际检查输入:jQuery('input').prop('checked', true);
David Sinclair 2014年

6
return false;等价于`evt.stopPropagation(); evt.preventDefault(); (在jQuery中
罗勒2015年

193

我尝试通过添加以下方法来添加上述解决方案:

evt.stopPropagation();
evt.preventDefault();

但是没有用 但是添加以下内容:

evt.stopImmediatePropagation();

解决了问题!:)


6
我不知道为什么,但是您所说的对我的代码来说似乎很有效。谢谢!
shaosh 2015年

8
完善。这很好!虽然evt.stopPropagation(); evt.preventDefault();没有;但不是
James111

1
只有这对我有用,我尝试了其他功能但没有成功
gardarvalur

1
这个答案救了我一命!谢谢:D
Bluetree

1
这就是我的答案!
Dyluck

73

将click事件绑定到输入而不是标签。单击标签时-事件仍然会发生,因为正如Dustin提到的,单击标签会触发对输入的单击。这将使标签保持其正常功能。

$('input').click();

代替

$('label').click();

10
如果您的标记使用了标签包裹输入技术,并且刚刚保存了我的理智,则此解决方案也有效:o)
Whelkaholism 2012年

4
实际上,您change甚至应该绑定到单选按钮上,因为标签的文本是可单击的-它们并不总是单击单选按钮本身。
chovy

2
如果使用Bootstrapesque label > input设置,则这是答案,而不是答案。在代码中添加evt.stopPropagation()或添加evt.preventDefault()代码虽然很有效,但是当正确的解决方案更加简洁高效时,应该避免使用hack。
elPastor

哇,哇,我花了将近两天的时间弄清楚,最终这有所帮助,并非常感谢您的解释
开源开发人员

这挽救了我的一天!
gab06

11

如果您尝试使用外部容器作为click元素,则还可以让事件自然冒泡,并在click处理程序中测试所需的元素。如果您尝试为表单设置唯一的单击区域,则此方案很有用。

<form>
<div id="outer">
    <label for="mycheckbox">My Checkbox</label>
    <input type="checkbox" name="mycheckbox" id="mycheckbox" value="on"/>
</div>
</form>
<script>
$('#outer').on('click', function(e){
    // this fires for #outer, label, and input
    if (e.target.tagName == 'INPUT'){
        // only interested in input
        console.log(this);
    }
});
</script>

1
这对我有用,因为我仍然希望选择单选按钮。我只是不希望事件处理程序对所有操作执行两次。
chovy

1
这将不允许选择孩子。顺便说一句,实现相同功能的一个更好的选择是if (e.target == e.currentTarget) {}
鸡汤

9

要解决此简单问题,请删除标签上的“ for”属性。单击标签也将触发相关元素的单击。(在您的情况下,这会触发两次点击事件。)

祝好运


确实是快速解决方案。有人可能会说它搞砸了标记,但是我反对“ for”属性的目的是事件传播。因此,如果您使用其他机制(jquery),则一定要摆脱“ for”。
克里斯·哈灵顿

5

我通常会使用这种合成胶

.off('click').on('click', function () { console.log('click'); })

代替

.click(function () { console.log('click'); })

5

最佳答案隐藏在注释中:

实际上,您change甚至应该绑定到单选按钮上,因为标签的文本是可单击的-它们并不总是单击单选按钮本身。– chovy 13 年12月12日在1:45

拨弄说明,所有其他的解决方案- ,stopPropagation,,stopImmediatePropagation -无论是什么改变或破坏的复选框/收音机功能)。它还说明这是一个普通的JavaScript问题,而不是jQuery问题。preventDefaultreturn false

编辑: 我刚刚在另一个线程中发现的另一个可行的解决方案是将绑定onclick到输入而不是标签。更新小提琴



1

e.preventDefault()的问题;它会阻止标签点击检查单选按钮。

更好的解决方案是简单地添加“已检查”快速检查,如下所示:

$("label").click(function(e){
  var rbtn = $(this).find("input");
  if(rbtn.is(':checked')){
  **All the code you want to have happen on click**
  }
)};

1
更为简洁的解决方案将只是使用.mouseup而不是
.click

1
如果您的代码还将允许用户取消选择单选按钮,则此解决方案不起作用。在这种情况下,双重起火会造成严重的麻烦。
Johncl 2014年

1

我的问题有点不同,因为这evt.stopPropagation();evt.preventDefault();对我不起作用,我只添加return false;最后一个,然后就可以了。

$("#addressDiv").on("click", ".goEditAddress", function(event) {
    alert("halo");
    return false;
});

1

就我而言,问题是我在函数中有click事件,并且函数执行了两次 ..函数的每次执行都会创建一个新的click事件。- 捂脸 -

将click事件移到函数外部后,一切按预期进行!:)


0

尝试将输入标签放置在触发元素之外,因为标签标签模拟点击,因此您将始终有多个调用。


0

我遇到了同样的问题,因为我已经将无线电广播像这样嵌套在标签内,并将处理程序附加到radio_div。删除嵌套标签可解决此问题。

<div id="radio_div">
    <label>
       <input type="radio" class="community_radio" name="community_radio" value="existing">
           Add To Existing Community
    </label>
</div>

0

标签触发要选中的单选框/复选框。

if ($(event.target).is('label')){
    event.preventDefault();
}

它尤其防止标签触发此行为。


0

单击具有for =“ some-id”属性的标签会触发新的点击,但前提是目标存在并且是输入。我无法使用e.preventDefault()或类似的东西完美地解决它,所以我这样做是这样的:

例如,如果您具有此结构,并且想要在单击.some-class时发生事件

<div class="some-class">
    <input type=checkbox" id="the-input-id" />
    <label for="the-input-id">Label</label>
</div>

起作用的是:

$(document)
    .on('click', '.some-class', function(e) {
        if(
            $(e.target).is('label[for]')
            &&
            $('input#' + $(e.target).attr('for')).length
        ) {
            // This will trigger a new click so we are out of here
            return;
        }

        // else do your thing here, it will not get called twice
    })
;
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.