为什么在父元素上使用preventDefault()点击'禁用'一个复选框?

时间:2013-04-02 14:42:52

标签: javascript html checkbox preventdefault stoppropagation

我最近遇到过这种情况(这里简化)。只需用一个元素包装一个复选框,并在它的click事件上应用preventDefault(),然后该复选框将被取消选中。

请参阅this fiddle,但这是一个剪辑:

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

/* Wrapper could be any element (and any ancestor element will work) */
$('div').on('click', function(e){
    e.preventDefault();
});


/* Uncomment to make the checkbox work again 
$('input').on('click', function(e){
    e.stopPropagation();
});
*/

行为发生在Chrome和FF中,因此我认为这是故意的。

为什么已经在复选框上触发的click事件不会导致复选框被切换?祖先的preventDefault似乎应该与子复选框的行为无关。似乎,为了发生复选框更改,click事件需要一直自由地冒泡到文档根目录。

这里发生了什么?

2 个答案:

答案 0 :(得分:11)

  

对祖先的preventDefault似乎应该与子复选框的行为无关。

不,不是真的。事件起泡,所有处理程序(包括祖先的处理程序)都可能会影响它。

  

似乎,为了发生复选框更改,click事件需要一直自由地冒泡到文档根目录。

不完全是。它不需要到达文档根目录,但它不能被默认阻止。

您可能希望在event flowdefault actions and cancelable events上阅读DOM规范中的体系结构说明。

那么一步一步发生什么呢?

  1. 您点击复选框
  2. 检查
  3. 事件将在文档根目录
  4. 上发送
  5. (不在IE中):capture phase,您的处理程序没有任何反应
  6. 活动到达<input>
  7. ......并开始冒泡
  8. <div>上,它会被处理。您的事件侦听器调用preventDefault方法,设置内部cancelled标记。
  9. 泡沫,但没有任何事情发生。
  10. 由于事件已取消,因此不应执行默认操作,并将复选框重置为之前的状态。
  11. 如果您取消注释代码的第二部分,则步骤6+看起来不同:

    1. 该事件由<input>处理。您的监听器调用stopPropagation方法
    2. ...导致跳过冒泡阶段。 (div-listener永远不会被调用)
    3. 未阻止默认操作,并且复选框保持选中状态。

答案 1 :(得分:5)

preventDefault可防止触发浏览器的默认操作。更改复选框的选中状态或跟随锚点的href,提交表单等是默认操作。 preventDefault在允许事件传播的同时阻止它们。

这与事件传播不同(您可以 - 正如您所指出的那样 - 停靠stopPropagation)。在调用浏览器的默认行为之前,事件将在整个侦听器层次结构中传播(除非被阻止)。