Javascript Can';t使用preventDefault()以编程方式检查单选按钮

Javascript Can';t使用preventDefault()以编程方式检查单选按钮,javascript,jquery,Javascript,Jquery,我有一些元素(例如带有class.label的div),每个元素内部都有单选按钮。当用户单击此“标签”时,我通过编程将其中的收音机设置为选中状态。但是,如果我对click事件使用preventDefault(),则如果用户完全单击了收音机,则收音机不会被选中 请帮助我理解这种奇怪的行为我知道解决方案,我知道父元素上的preventDefault()为什么不允许检查收音机,但我想了解,为什么收音机上的单击事件可以不允许以编程方式设置其状态。您将看到,单击单选按钮将显示收音机已选中,但未选中 $(

我有一些元素(例如带有class.label的div),每个元素内部都有单选按钮。当用户单击此“标签”时,我通过编程将其中的收音机设置为选中状态。但是,如果我对click事件使用preventDefault(),则如果用户完全单击了收音机,则收音机不会被选中

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

$(函数(){
$('.label')。在('click',函数(e)上{
var$radio=$(this.find(“:radio”)
log('before prevent','checked=${$radio.prop('checked')}`,'prevented=${e.isDefaultPrevented()}`);
e、 预防默认值();
if(!$(this).hasClass('checked')){
$('.checked').removeClass('checked');
$(this.addClass('checked');
}
$radio.prop('checked',true);
log('after prevent','checked=${$radio.prop('checked')}`,'prevented=${e.isDefaultPrevented()}`);
setTimeout(函数(){
log('after timeout','checked=${$radio.prop('checked')}`);
}, 500);
});
$(':radio')。在('click',函数(e)上{
log('click','prevented=${e.isDefaultPrevented()}');
});
});
.label{
填充:10px;
边缘底部:10px;
边框:1px实心#000;
}
.标签{
背景颜色:绿色;
}

标签1
标签2

您只需添加
e.stopPropagation()
即可再次返回选中的单选按钮的默认功能

其行为是,您的
收音机
div的子对象
,您的
单击
侦听器基于父对象
div
,当您
preventDefault
时,子对象也会继承预防

检查

如果在一个元素上按下按钮并在另一个元素上释放,则事件将在包含这两个元素的最特定的祖先元素上触发

对父元素使用preventDefault()可以防止触发原始事件,但不会停止传播。理解层次结构和事件传播是至关重要的

您的代码片段中有部分解决方案。如果您注释掉了那一行,代码就会正常工作,正如您所期望的那样。 但是如果你使用

e.stopPropagation();
它也起作用

为了避免重复web上已有的信息,我在这里找到了一个非常类似的例子(),它可以帮助您更好地理解事件传播和冒泡

您还可以在这里找到更好的解释()


MDN文档也很少会给人留下深刻印象()。

我如何看待这种情况(受以下启发):

  • 你点击收音机
  • 它会被检查
  • 事件在文档根目录上调度
  • 捕获阶段,处理程序不会发生任何事情
  • 事件到达
  • …然后开始冒泡
  • 上,它被处理。事件侦听器调用
    preventDefault
    方法,设置内部
    cancelled
    标志<代码>获取类“.checked”并再次将收音机设置为选中,现在以编程方式进行
  • 事件气泡继续,但不再发生任何事情
  • 由于事件已被取消,因此默认操作不应发生,即使以编程方式选中复选框,复选框也会重置为以前的状态

  • 您是否有任何理由需要使用
    e.preventDefault()
    ?默认情况下,
    不是可单击的元素,因此它上没有与本机单击事件相关联的操作。顺便说一句,请使用语义。标签应该是
    标签
    @Terry我可以删除e.preventDefault(),但当我遇到这种情况时,我决定找出为什么我不能通过编程检查收音机,如果它上的click事件设置为preventDefault()@QuentinVeron我简化了这段代码,事实上结构更复杂,可能重复的仍然不起作用。单击单选按钮不会检查它?我认为,您必须添加额外的单击处理程序到内置StopRopagation()的收音机中,并通过编程方式单击标签。但是,正如我在问题中所说,我知道解决方案,我想了解行为。谢谢你,我想,第一链接的答案澄清了我的情况。我已经更新了我的问题