首页 > 解决方案 > 无法使用 preventDefault() 以编程方式检查单选按钮

问题描述

我有一些元素(例如带有类 .label 的 div),其中每个元素都带有单选按钮。当用户单击此“标签”时,我以编程方式将其中的单选设置为选中状态。但是,如果我将 preventDefault() 用于单击事件,则如果用户完全单击了收音机,则不会选择收音机。

请帮助我理解这种奇怪的行为。我知道解决方案,我知道为什么 parent 元素上的 preventDefault() 不允许检查收音机,但我想了解,为什么收音机上的 click 事件不允许以编程方式设置其状态。您会看到单击单选按钮会说已选中单选,但事实并非如此。

$(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>

更新。我如何看待这种情况:

  1. 用户点击收音机
  2. 首先在收音机上触发事件并将输入设置为选中。
  3. 然后事件冒泡并触发.label
  4. 调用 preventDefault() 会设置一个内部cancelled标志。
  5. div现在以编程方式再次将“.checked”类和收音机设置为已检查。
  6. 事件冒泡,但不再发生任何事情。
  7. 由于事件已取消,因此不应发生默认操作,并且复选框将重置为之前的状态。

我对吗?

标签: javascriptjquery

解决方案


我如何看待这种情况(受https://stackoverflow.com/a/15767580/11357125启发):

  1. 你点击收音机
  2. 它被检查
  3. 该事件在文档根目录上调度
  4. 捕获阶段,您的处理程序没有任何反应
  5. 活动到达<input>
  6. ……开始冒泡
  7. 在 上<div>,它被处理。事件监听器调用该preventDefault方法,设置一个内部cancelled标志。现在以编程方式再次<div>将“.checked”类和收音机设置为已检查。
  8. 事件冒泡,但不再发生任何事情。
  9. 由于事件已取消,因此不应发生默认操作,并且即使在以编程方式选中复选框后,复选框也会重置为之前的状态。

推荐阅读