为什么在调用event.preventDefault()后用JavaScript文件切换复选框/单选按钮?

时间:2014-02-25 13:18:19

标签: javascript jquery dom javascript-events checkbox

请考虑以下示例代码:

<span>
    <input type="checkbox">
</span>

$('span').click(function(e) {
    e.preventDefault();
    $(':checkbox')[0].checked = true;
});

Fiddle

据我所知,这应该发生:

  • preventDefault()应该阻止浏览器的默认行为检查复选框,即使事件处理程序附加在DOM层次结构的上方也是如此。这部分工作正常。
  • 设置.checked = true应该有效,我相信它应该独立于浏览器对我已取消的事件的默认操作。这部分似乎有些错误,好像preventDefault()正在影响它 - 删除preventDefault()并按预期工作。

该复选框始终未选中的实际原因是什么?

我在Chrome 33和Firefox 27上测试过,所以这似乎不是浏览器错误。

这个问题主要是由于好奇心扩展我的DOM /事件模型知识。我不想要解决方法,而是想知道为什么这个例子失败了。

4 个答案:

答案 0 :(得分:4)

鉴于你的HTML:

<span>
    <input type="checkbox">
</span>

和你的代码:

$('span').click(function(e) {
    e.preventDefault();
    $(':checkbox')[0].checked = true;
});

事件冒泡是你的问题。

点击checkbox后,点击事件会传播到spane.preventDefault()是从checkbox传播的事件对象的调用。

因此preventDefault()针对checkbox本身执行,阻止对其进行检查。

checkbox的点击事件通过preventDefault被“取消”,它将一直保持取消,直到事件流程完成。 (有关详细信息,请参阅答案底部)

如果您在某个范围内应用了某些样式,则会发现点击checkbox代码的工作方式符合预期,但点击checkbox本身会因上述问题而复制您的问题。


DEMO - 原始小提琴+风格。点击span即可,checkbox不是


根据MDN documentation on preventDefault()

  

在事件流程的任何阶段调用preventDefault取消   事件,意味着通常采取的任何默认操作   由于事件的实施不会发生。

DOM Level 2 Spec还注明:

  

如果事件可取消,则使用preventDefault方法   表示该事件将被取消,表示任何默认操作   由于事件通常采取的执行不会   发生。 在事件流的任何阶段,如果是preventDefault方法   被称为事件被取消

示例5中的DOM Level 3 Events Spec注释:

  

click元素上的<input type="checkbox">事件相关联的默认操作会切换该元素的checked IDL属性值。如果取消click事件的默认操作,则该值将恢复为以前的状态。

答案 1 :(得分:3)

setTimeout中包含部分代码可以解决问题,正如您在此处所见http://jsfiddle.net/y7C77/

$('span').click(function(e) {
    e.preventDefault();
    setTimeout(function () {
        $('input').prop('checked', true);
    }, 1);
});

preventDefault()取消默认操作,我认为即使您手动执行浏览器操作,它也可以取消它(在这种情况下:更改checked属性)。

答案 2 :(得分:2)

这是我感觉到的预期行为,因为当你说event.preventDefault()时,你指示浏览器在这个事件中不对它做任何操作。因此,即使在您明确选中复选框的语句之后,浏览器也不会对其执行任何操作。 当我按如下方式更改事件时,我们可以看到差异:

$('span').click(function(e) {
     e.preventDefault();
     //$(':checkbox')[0].checked = true;
     setTimeout(function(){$(':checkbox')[0].checked = true;});
});

使用超时我们正在更改事件外的checked属性,因此会检查它。

答案 3 :(得分:1)

您必须preventDefault同时clickmouseup并设置选中mouseup

尝试:

$('span').click(function(e) {
    e.preventDefault();
}).mouseup(function(e){
    e.preventDefault();
    $(':checkbox')[0].checked = true;
});