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>

มีวิธีแก้ปัญหาสำหรับพฤติกรรมนี้หรือไม่?

คำตอบ:


130

ลองเพิ่ม:

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

ไปที่. ผูก () หรือ. คลิก () แล้วแต่คุณจะเห็น นอกจากนี้ให้เพิ่มพารามิเตอร์evtลงในฟังก์ชันเช่นfunction(evt) {...


9
ทำไมถึงเกิดขึ้น?
chovy

8
เนื่องจากมีรายการที่ซ้อนกัน. แต่ละรายการในลำดับชั้นจะแสดงเหตุการณ์
จอร์แดน

7
หากคุณกำลังใช้สิ่งนี้สำหรับช่องทำเครื่องหมายฉันจำเป็นต้องเปิดใช้งานอินพุตเพื่อตรวจสอบจริงด้วย:jQuery('input').prop('checked', true);
David Sinclair

6
return false;เทียบเท่ากับ `evt.stopPropagation (); evt.preventDefault (); ( ใน jQuery )
โหระพา

193

ฉันลองเพิ่มโซลูชันด้านบนโดยเพิ่ม:

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

แต่ไม่ได้ผล อย่างไรก็ตามการเพิ่มสิ่งนี้:

evt.stopImmediatePropagation();

แก้ปัญหา! :)


6
ฉันไม่รู้ว่าทำไม แต่สิ่งที่คุณพูดดูเหมือนจะใช้ได้กับรหัสของฉัน ขอบคุณ!
shaosh

8
สมบูรณ์ มันใช้ได้ดี! แม้ว่าจะevt.stopPropagation(); evt.preventDefault();ไม่ได้; 't
James111

1
สิ่งนี้ใช้ได้ผลสำหรับฉันเท่านั้นฉันได้ลองฟังก์ชั่นอื่น ๆ แล้วไม่ประสบความสำเร็จ
gardarvalur

1
คำตอบนี้ช่วยชีวิตฉัน! ขอบคุณ: D
Bluetree

1
นี่คือคำตอบสำหรับฉัน!
Dyluck

73

เชื่อมโยงเหตุการณ์การคลิกกับอินพุตแทนที่จะเป็นป้ายกำกับ เมื่อคลิกป้ายกำกับ - เหตุการณ์จะยังคงเกิดขึ้นเนื่องจากดัสตินกล่าวถึงการคลิกที่ป้ายกำกับจะทำให้เกิดการคลิกที่อินพุต ซึ่งจะช่วยให้ป้ายกำกับสามารถใช้งานได้ตามปกติ

$('input').click();

แทน

$('label').click();

10
วิธีนี้ใช้งานได้เช่นกันหากมาร์กอัปของคุณใช้เทคนิคการห่อฉลาก - การป้อนข้อมูลและช่วยประหยัดสติของฉัน: o)
Whelkaholism

4
จริงๆแล้วคุณควรเชื่อมโยงchangeแม้กระทั่งบนปุ่มตัวเลือกเนื่องจากข้อความของป้ายกำกับสามารถคลิกได้ - พวกเขาไม่ได้คลิกปุ่มตัวเลือกเสมอไป
chovy

2
หากใช้การlabel > inputตั้งค่าBootstrapesque นี่คือคำตอบไม่ใช่คำตอบ การเพิ่มevt.stopPropagation()หรือevt.preventDefault()ลงในโค้ดของคุณในขณะที่มีประสิทธิภาพคือการแฮ็กที่ควรหลีกเลี่ยงเมื่อโซลูชันที่เหมาะสมนั้นสะอาดและมีประสิทธิภาพมากขึ้น
elPastor

ว้าวว้าวว้าวฉันใช้เวลาเกือบสองสามวันในการค้นหาในที่สุดสิ่งนี้ก็ช่วยได้และขอบคุณมากสำหรับคำอธิบาย
ผู้พัฒนา opensource

วันนี้ช่วยฉันไว้!
gab06

11

หากคุณกำลังพยายามใช้คอนเทนเนอร์ภายนอกเป็นองค์ประกอบการคลิกคุณยังสามารถปล่อยให้เหตุการณ์เกิดขึ้นตามธรรมชาติและทดสอบองค์ประกอบที่คาดหวังในตัวจัดการคลิกของคุณ สถานการณ์นี้มีประโยชน์หากคุณกำลังพยายามจัดรูปแบบโซนคลิกเฉพาะสำหรับฟอร์ม

<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
ซึ่งจะไม่อนุญาตให้เลือกเด็ก BTW เป็นตัวเลือกที่ดีกว่าที่จะให้เกิดการทำงานที่เหมือนกันจะเป็นif (e.target == e.currentTarget) {}
ซุปไก่

9

ในการแก้ไขปัญหานี้ด้วยวิธีง่ายๆให้ลบแอตทริบิวต์ "for" บนป้ายกำกับ การคลิกที่ป้ายกำกับจะทำให้เกิดการคลิกที่องค์ประกอบที่เกี่ยวข้อง (ซึ่งในกรณีของคุณคือทำให้เหตุการณ์คลิกของคุณเริ่มทำงานสองครั้ง)

โชคดี


แน่นอนวิธีแก้ปัญหาอย่างรวดเร็ว อาจมีคนแย้งว่ามันยุ่งกับมาร์กอัป แต่ฉันขอโต้กลับว่าจุดประสงค์ของแอตทริบิวต์ "for" คือการนำเสนอเหตุการณ์ ดังนั้นหากคุณใช้กลไกอื่น (jquery) ให้กำจัด "for" ออกไป
Chris Harrington

5

ฉันมักจะใช้ synthax นี้

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

แทน

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

5

คำตอบที่ดีที่สุดซ่อนอยู่ในความคิดเห็น:

จริงๆแล้วคุณควรเชื่อมโยงchangeแม้กระทั่งบนปุ่มตัวเลือกเนื่องจากข้อความของป้ายกำกับสามารถคลิกได้ - พวกเขาไม่ได้คลิกปุ่มตัวเลือกเสมอไป - chovy 12 ธ.ค. 56 เวลา 1:45 น

นี้ซอแสดงให้เห็นว่าทุกคนที่แก้ปัญหาอื่น ๆ - stopPropagation, stopImmediatePropagation, preventDefault, return false- ทั้งการเปลี่ยนแปลงอะไรหรือทำลายช่องทำเครื่องหมาย / ฟังก์ชั่นวิทยุ) นอกจากนี้ยังแสดงให้เห็นว่านี่เป็นปัญหา JavaScript ของวานิลลาไม่ใช่ปัญหา jQuery

แก้ไข: วิธีการทำงานอีกอย่างที่ฉันเพิ่งพบในเธรดอื่นคือการผูกเข้าonclickกับอินพุตแทนที่จะเป็นเลเบล ปรับปรุงซอ .


2

ฉันได้ลองโดยการเพิ่มโซลูชัน

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

แต่ไม่ได้ผล

โดยการเพิ่ม

evt.stopImmediatePropagation();

แก้ปัญหา! :)


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 แทน. คลิก
yoshyosh

1
วิธีนี้ใช้ไม่ได้หากรหัสของคุณอนุญาตให้ผู้ใช้ยกเลิกการเลือกปุ่มตัวเลือก ไฟสองครั้งทำให้เกิดปัญหาร้ายแรงในกรณีนี้
Johncl

1

ปัญหาของฉันแตกต่างออกไปเล็กน้อยเนื่องจากevt.stopPropagation();evt.preventDefault();ไม่ได้ผลสำหรับฉันฉันแค่เพิ่มreturn false;ในตอนท้ายแล้วมันก็ใช้ได้

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

1

ในกรณีของฉันปัญหาคือฉันมีเหตุการณ์คลิกในฟังก์ชันและฟังก์ชันถูกเรียกใช้สองครั้ง .... ทุกการทำงานของฟังก์ชันจะสร้างเหตุการณ์การคลิกใหม่ - เฟซปาล์ม -

หลังจากย้ายเหตุการณ์คลิกออกนอกฟังก์ชั่นทุกอย่างก็เป็นไปตามที่คาดไว้! :)


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 () หรือสิ่งต่างๆเช่นนั้นฉันจึงทำเช่นนี้:

ตัวอย่างเช่นหากคุณมีโครงสร้างนี้และต้องการให้มีเหตุการณ์ในการคลิก. บางคลาส

<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
    })
;
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.