简体   繁体   English

无法使用preventDefault()以编程方式检查单选按钮

[英]Can't check radio button programmatically with preventDefault()

I have some elements (for example divs with class .label) with radio buttons inside of each. 我有一些元素(例如带有类.label的div),每个元素都有单选按钮。 When user clicks this "labels" I programmatically set radio in it as selected. 当用户单击此“标签”时,我以编程方式将其中的无线电设置为已选中。 But if I use preventDefault() for click event, the radio didn't selected if user clicked exactly on radio. 但是如果我使用preventDefault()进行点击事件,如果用户完全点击无线电,则无法选择收音机。

Please help me to understand this strange behaviour. 请帮我理解这种奇怪的行为。 I know the solution, I know why preventDefault() on parent element disallows to check radio, but I want to understand, why click event on radio can disallow to set its state programmatically . 我知道解决方案,我知道为什么在父元素上的preventDefault()不允许检查无线电,但我想明白,为什么无线电上的click事件可以禁止以编程方式设置其状态 You will see that click on radio button will say that radio is checked, but it's not. 你会看到单击单选按钮会说收音机已被选中,但事实并非如此。

 $(function () { $('.label').on('click', function(e) { var $radio = $(this).find(':radio') console.log('before prevent', `checked=${$radio.prop('checked')}`, `prevented=${e.isDefaultPrevented()}`); e.preventDefault(); if (!$(this).hasClass('checked')) { $('.checked').removeClass('checked'); $(this).addClass('checked'); } $radio.prop('checked', true); console.log('after prevent', `checked=${$radio.prop('checked')}`, `prevented=${e.isDefaultPrevented()}`); setTimeout(function () { console.log('after timeout', `checked=${$radio.prop('checked')}`); }, 500); }); $(':radio').on('click', function (e) { console.log('click', `prevented=${e.isDefaultPrevented()}`); }); }); 
 .label { padding: 10px; margin-bottom: 10px; border: 1px solid #000; } .label.checked { background-color: green; } 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <div class="label"> Label 1 <input type="radio" name="radio" value="1"> </div> <div class="label"> Label 2 <input type="radio" name="radio" value="2"> </div> 

UPDATE . 更新 How do I see this situation: 我怎么看这种情况:

  1. User clicks on radio 用户点击广播
  2. Firstly event triggered on radio and input setted as checked. 首先在无线电上触发事件,并将输入设置为已检查。
  3. Then event is bubbling up and triggered on .label 然后事件冒泡并在.label上触发
  4. Calling preventDefault() sets up an internal cancelled flag. 调用preventDefault()会设置内部cancelled标志。
  5. div getting class '.checked' and radio setted as checked again, now programmatically. div将类'.checked'和radio设置为再次检查,现在以编程方式。
  6. Event bubbles on, but nothing happens any more. 事件泡沫,但没有任何事情发生。
  7. Since the event was cancelled, the default action should not occur and the checkbox is reset to its previous state. 由于事件已取消,因此不应执行默认操作,并将复选框重置为其先前状态。

Am I right? 我对吗?

How do I see this situation (inspired by https://stackoverflow.com/a/15767580/11357125 ): 我如何看待这种情况(受https://stackoverflow.com/a/15767580/11357125启发):

  1. You click on the radio 你点击收音机
  2. It gets checked 它被检查
  3. The event is dispatched on the document root 该事件将在文档根目录上分派
  4. Capture phase, nothing happens with your handlers 捕获阶段,处理程序没有任何反应
  5. The event arrives at the <input> 事件到达<input>
  6. …and begins to bubble ......并开始冒泡
  7. On the <div> , it is handled. <div> ,它被处理。 Event listener calls the preventDefault method, setting an internal cancelled flag. 事件侦听器调用preventDefault方法,设置内部cancelled标志。 <div> getting class '.checked' and radio setted as checked again, now programmatically . <div>将类'.checked'和radio设置为再次检查,现在以编程方式
  8. Event bubbles on, but nothing happens any more. 事件泡沫,但没有任何事情发生。
  9. Since the event was cancelled, the default action should not occur and the checkbox is reset to its previous state even after it was checked programmatically . 由于事件已取消,因此即使在以编程方式检查后,也不会发生默认操作,并且复选框将重置为其先前状态。

Using preventDefault() on parent elements prevent the original event to be fired, but does not stop propagation. 在父元素上使用preventDefault()可以防止触发原始事件,但不会停止传播。 Understanding hierarchy and event propagation is crucial. 了解层次结构和事件传播至关重要。

You have part of the solution in your code snippet. 您的代码段中包含部分解决方案。 If you comment out that particular line, the code works properly, like you would expect. 如果您注释掉该特定行,则代码可以正常工作,就像您期望的那样。 But if you use 但如果你使用

e.stopPropagation();

it also works. 它也有效。

In order not to repeat information already on the web, I found a very similar case here ( Why does preventDefault() on a parent element's click 'disable' a checkbox? ) which may help you understand better event propagation and bubbling. 为了不重复网上已有的信息,我在这里找到了一个非常相似的案例( 为什么在父元素点击'禁用'一个复选框?上的preventDefault()?这可能有助于你理解更好的事件传播和冒泡。

You can also find an even better explanation here ( https://medium.freecodecamp.org/a-simplified-explanation-of-event-propagation-in-javascript-f9de7961a06e ). 您还可以在此处找到更好的解释( https://medium.freecodecamp.org/a-simplified-explanation-of-event-propagation-in-javascript-f9de7961a06e )。

MDN documentation also rarely fails to impress ( https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault ). MDN文档也很少令人印象深刻( https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault )。

You just need to add e.stopPropagation() to return the default functionality for radio button again which is checked 您只需要添加e.stopPropagation()以再次返回checked单选按钮的默认功能

The behaviour is that You have radio is a child to the div and you click listener is based on the parent div and when you preventDefault then the children inherit the prevention as well. 行为是你有radiodiv的孩子,你click监听器是基于父div ,当你preventDefault ,孩子也继承了预防。

check that 检查一下

If the button is pressed on one element and released on a different one, the event is fired on the most specific ancestor element that contained both. 如果按下一个元素上的按钮并在另一个元素上释放,则会在包含这两个元素的最具体的祖先元素上触发该事件。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM