jQuery Click kích hoạt hai lần khi nhấp vào nhãn


114

Tôi đang sử dụng jQuery để tạo các nút radio tùy chỉnh và tôi gặp sự cố. Khi nhấp vào nhãn liên kết với radio, các sự kiện nhấp chuột sẽ kích hoạt hai lần, nếu tôi chỉ nhấp vào radio thì nó hoạt động tốt (thực ra không phải radio mà tôi đang nhấp mà là div bao bọc toàn bộ đầu vào và nhãn). Đây là mã:

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>

Có giải pháp nào cho hành vi này không?

Câu trả lời:


130

Hãy thử thêm:

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

sang .bind () hoặc .click (), bất kỳ cái nào bạn đang thấy. Ngoài ra, hãy thêm tham số evtvào hàm, nhưfunction(evt) {...


9
lý do tại sao điều này xảy ra?
chovy 12/1213

8
Vì có các mục lồng vào nhau. Mỗi mục trong hệ thống phân cấp sẽ xuất hiện sự kiện.
Jordan

7
Nếu bạn đang sử dụng này cho một hộp kiểm, điều này cũng là cần thiết đối với tôi để cho phép các đầu vào để thực sự được kiểm tra:jQuery('input').prop('checked', true);
David Sinclair

6
return false;tương đương với `evt.stopPropagation (); evt.preventDefault (); ( trong jQuery )
húng quế

193

Tôi đã thử thêm giải pháp ở trên bằng cách thêm:

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

nhưng không hoạt động. Tuy nhiên thêm điều này:

evt.stopImmediatePropagation();

Đã giải quyết vấn đề! :)


6
Tôi không biết tại sao, nhưng những gì bạn nói có vẻ phù hợp với mã của tôi. Cảm ơn bạn!
shaosh

8
Hoàn hảo. Điều này hoạt động tốt! Mặc dù evt.stopPropagation(); evt.preventDefault();không; 't
James111

1
chỉ điều này làm việc với tôi, tôi đã thử các chức năng khác mà không thành công
gardarvalur 27/09/2016

1
Câu trả lời này đã cứu mạng tôi! Cảm ơn: D
Bluetree 17/01/18

1
Đây là câu trả lời cho tôi!
Dyluck

73

Liên kết sự kiện nhấp chuột với đầu vào thay vì nhãn. Khi nhãn được nhấp vào - sự kiện vẫn sẽ xảy ra vì như Dustin đã đề cập, một lần nhấp vào nhãn sẽ kích hoạt một lần nhấp vào đầu vào. Điều này sẽ cho phép nhãn giữ chức năng bình thường của nó.

$('input').click();

Thay vì

$('label').click();

10
Giải pháp này cũng làm việc nếu đánh dấu của bạn sử dụng các kỹ thuật nhãn và đóng gói-the-đầu vào, và chỉ lưu sự tỉnh táo của tôi: o)
Whelkaholism

4
bạn thực sự nên liên kết với changengay cả trên nút radio vì văn bản của nhãn có thể nhấp được - chúng không phải lúc nào cũng nhấp vào chính nút radio.
chovy 12/1213

2
Nếu sử dụng label > inputthiết lập Bootstrapesque , đây là câu trả lời, không phải câu trả lời. Thêm evt.stopPropagation()hoặc evt.preventDefault()vào mã của bạn, mặc dù có hiệu quả, là một hành vi tấn công nên tránh khi giải pháp thích hợp sạch hơn và hiệu quả hơn nhiều.
elPastor

wow wow wow chỉ, tôi đã dành gần một vài ngày tìm ra, cuối cùng điều này đã giúp và cảm ơn rất nhiều cho lời giải thích
opensource-phát triển

điều này đã cứu ngày của tôi!
gab06

11

Nếu bạn đang cố gắng sử dụng vùng chứa bên ngoài làm phần tử nhấp chuột, bạn cũng có thể để các sự kiện bong bóng tự nhiên và kiểm tra phần tử mong đợi trong trình xử lý nhấp chuột của bạn. Tình huống này hữu ích nếu bạn đang cố gắng tạo kiểu cho vùng nhấp chuột duy nhất cho biểu mẫu.

<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
Điều này phù hợp với tôi vì tôi vẫn muốn nút radio được chọn. Tôi chỉ không muốn trình xử lý sự kiện làm mọi thứ hai lần.
chovy 14/1213

1
Điều này sẽ không cho phép trẻ em được chọn. BTW, một lựa chọn tốt hơn để đạt được chức năng tương tự sẽ làif (e.target == e.currentTarget) {}
Chicken Soup

9

Để khắc phục điều này một cách dễ dàng, hãy xóa thuộc tính "for" trên nhãn. Một lần nhấp vào nhãn cũng sẽ kích hoạt một lần nhấp vào phần tử được liên kết. (trong trường hợp của bạn sẽ kích hoạt sự kiện nhấp chuột của bạn hai lần.)

Chúc may mắn


Quả thực là giải pháp nhanh chóng. Người ta có thể tranh luận rằng nó đang gây rối với đánh dấu, nhưng tôi phản đối rằng mục đích của thuộc tính "for" là đề xuất sự kiện. Vì vậy, nếu bạn đang sử dụng một cơ chế khác (jquery) thì hãy loại bỏ "for".
Chris Harrington

5

Tôi thường sử dụng cú pháp này

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

thay vì

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

5

Câu trả lời hay nhất được ẩn bên trong các bình luận:

bạn thực sự nên liên kết với changengay cả trên nút radio vì văn bản của nhãn có thể nhấp được - chúng không phải lúc nào cũng nhấp vào chính nút radio. - chovy 12/1213 lúc 1:45

Đây fiddle minh họa rằng tất cả các giải pháp khác - stopPropagation, stopImmediatePropagation, preventDefault, return false- một trong hai thay đổi gì hoặc phá hủy các chức năng hộp / radio). Nó cũng minh họa rằng đây là một vấn đề JavaScript vani, không phải là một vấn đề jQuery.

CHỈNH SỬA: Một giải pháp làm việc khác mà tôi vừa tìm thấy trong một luồng khác là liên kết onclickvới đầu vào thay vì nhãn. Cập nhật fiddle .


2

Tôi đã thử bằng cách thêm giải pháp.

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

nhưng không hoạt động.

Bằng cách thêm

evt.stopImmediatePropagation();

Đã giải quyết vấn đề! :)


1

Sự cố với e.preventDefault (); là nó ngăn việc nhấp vào nhãn kiểm tra nút radio.

Một giải pháp tốt hơn là chỉ cần thêm kiểm tra nhanh "được kiểm tra" như sau:

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

1
Một giải pháp thậm chí ngắn gọn hơn sẽ chỉ sử dụng .mouseup hơn .click
yoshyosh

1
Giải pháp này không hoạt động nếu mã của bạn cũng sẽ cho phép người dùng bỏ chọn một nút radio. Vụ cháy kép gây ra những rắc rối nghiêm trọng trong trường hợp này.
Johncl

1

Vấn đề của tôi hơi khác một chút, vì evt.stopPropagation();evt.preventDefault();nó không phù hợp với tôi, tôi chỉ thêm return false;vào cuối cùng, sau đó nó hoạt động.

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

1

Trong trường hợp của tôi, vấn đề là tôi có sự kiện nhấp chuột trong một hàmhàm được thực thi hai lần .... mỗi lần thực thi hàm sẽ tạo ra một sự kiện nhấp chuột mới. - facepalm -

sau khi di chuyển sự kiện nhấp chuột ra bên ngoài chức năng, mọi thứ hoạt động như mong đợi! :)


0

Hãy thử đặt thẻ đầu vào của bạn bên ngoài phần tử trình kích hoạt, vì thẻ nhãn mô phỏng nhấp chuột, vì vậy bạn sẽ luôn có nhiều lần gọi.


0

Tôi gặp sự cố tương tự vì tôi đã lồng radio của mình vào bên trong nhãn như thế này với trình xử lý được gắn vào radio_div. Xóa nhãn lồng nhau đã khắc phục sự cố.

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

0

Nhãn sẽ kích hoạt radio / hộp kiểm được chọn.

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

Nó đặc biệt ngăn chặn nhãn để kích hoạt hành vi này.


0

Nhấp chuột vào nhãn có thuộc tính for = "some-id" sẽ kích hoạt nhấp chuột mới, nhưng chỉ khi mục tiêu tồn tại và là đầu vào. Tôi không thể giải quyết nó một cách hoàn hảo với e.preventDefault () hoặc những thứ tương tự nên tôi đã làm như thế này:

Ví dụ: nếu bạn có cấu trúc này và muốn một sự kiện khi nhấp vào .some-class

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

Những gì đã làm là:

$(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
    })
;
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.