jQuery Клацніть пожежі двічі при натисканні на мітку


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();

до .bind () або .click (), що б ви не бачили. Також додайте параметр evtдо функції, наприкладfunction(evt) {...


9
чому це відбувається?
chovy

8
Тому що є вкладені елементи. Кожен елемент в ієрархії події буде міхур.
Йорданія

7
Якщо ви використовуєте це для прапорця, мені це також знадобилося, щоб увімкнути фактичну перевірку вводу:jQuery('input').prop('checked', true);
Девід Сінклер

6
return false;еквівалентно `evt.stopPropagation (); evt.preventDefault (); ( in jQuery )
базилік

193

Я спробував додати рішення вище, додавши:

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

але не вийшло. Однак додаючи це:

evt.stopImmediatePropagation();

вирішив проблему! :)


6
Я не знаю чому, але те, що ви сказали, виглядає як робота для мого коду. Дякую!
шаош

8
Ідеально. Це добре працювало! Хоча evt.stopPropagation(); evt.preventDefault();не був; 't
James111

1
тільки це працювало для мене, я безперешкодно пробував інші функції
gardarvalur

1
Ця відповідь врятувала мені життя! Дякую: D
Bluetree

1
Це була відповідь для мене!
Ділук

73

Прив’яжіть подію клацання до введення, а не до мітки. Після натискання мітки - подія все одно відбуватиметься, оскільки, як згадував Дастін, натискання на мітку викликає натискання на вхід. Це дозволить мітці зберігати свою нормальну функціональність.

$('input').click();

Замість

$('label').click();

10
Це рішення також працює, якщо ваша розмітка використовує техніку обтікання етикеток-введення, і я просто врятував мій розум: o)
Whelkaholism

4
насправді вам слід прив’язатись changeнавіть до перемикача, оскільки текст ярлика можна натискати - вони не завжди натискають сам перемикач.
chovy

2
Якщо ви використовуєте label > inputналаштування Bootstrapesque , це відповідь, а не відповідь. Додавання evt.stopPropagation()або evt.preventDefault()до свого коду, хоча воно є ефективним, - це хакер, якого слід уникати, коли правильне рішення набагато чистіше та ефективніше.
elPastor

уау вау просто вау, я витратив майже пару днів на роздуми, нарешті, це допомогло і дякую багато за пояснення
opensource-developer

це врятувало мені день!
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
Це не дозволить обирати дітей. До речі, кращим варіантом досягнення такої ж функціональності був биif (e.target == e.currentTarget) {}
Курячий суп

9

Щоб виправити це простим способом, видаліть на етикетці атрибут "for". Клацання мітки також спричинить натискання на пов'язаний елемент. (що у вашому випадку запускає вашу подію натискання двічі.)

Удачі


Справді швидке рішення. Можна стверджувати, що вона псується з розміткою, але я заперечую, що метою атрибуту "за" є пропонування подій. Тож якщо ви використовуєте інший механізм (jquery), то будь-якими способами позбудьтеся "для".
Кріс Харрінгтон

5

Я зазвичай використовую цей синтакс

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

замість

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

5

Найкраща відповідь прихована всередині коментарів:

насправді слід прив’язатись changeнавіть до перемикача, оскільки текст ярлика можна натискати - вони не завжди натискають на саму перемикач. - chovy 12 грудня 1313 о 1:45

Ця скрипка показує , що всі інші рішення - stopPropagation, stopImmediatePropagation, preventDefault, return false- або змінити нічого або не знищили / функціональність радіо прапорця). Це також ілюструє, що це проблема JavaScript ванілі, а не проблема jQuery.

EDIT: Ще одне робоче рішення, яке я щойно знайшов в іншому потоці, - прив’язати 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, а не .click
yoshyosh

1
Це рішення не працює, якщо ваш код також дозволить користувачеві скасувати вибір перемикача. Подвійний вогонь викликає серйозні неприємності в цьому випадку.
Джонкл

1

Моя проблема дещо інша, тому що evt.stopPropagation();evt.preventDefault();вона не працює для мене, я просто додаю, return false;врешті-решт, потім вона працює.

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

1

У моєму випадку проблема полягала в тому, що у мене була подія клацання у функції, і ця функція виконувалася двічі .... кожне виконання функції створює нову подію клацання. - facepalm -

після переміщення події клацання поза функцією все працювало як очікувалося! :)


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
    })
;
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.