9

我最近遇到了这种情况(这里简化)。只需用一个元素包装一个复选框并在其单击事件上应用 preventDefault() ,该复选框将变为不可选中。

看到这个小提琴,但这里有一个片段:

<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 中,所以我认为这是故意的。

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

这里发生了什么?

4

2 回答 2

12

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

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

似乎,要使复选框更改发生,单击事件需要自由地冒泡到文档根目录。

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

您可能想阅读 DOM 规范中关于事件流默认操作和可取消事件的架构说明。

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

  1. 你点击复选框
  2. 它被检查
  3. 该事件在文档根目录上调度
  4. (不在 IE 中):捕获阶段,您的处理程序没有任何反应
  5. 活动到达<input>
  6. ……开始冒泡
  7. 在 上<div>,它被处理。您的事件侦听器调用该preventDefault方法,设置一个内部cancelled标志。
  8. 它冒泡,但没有任何反应。
  9. 由于事件已取消,因此不应发生默认操作,并且复选框将重置为之前的状态。

如果您取消注释代码的第二部分,步骤 6+ 看起来会有所不同:

  1. 该事件在<input>. 您的侦听器调用该stopPropagation方法
  2. …这导致跳过冒泡阶段。(永远不会调用 div-listener)
  3. 未阻止默认操作,并且复选框保持选中状态。
于 2013-04-02T15:05:56.610 回答
5

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

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

于 2013-04-02T14:47:41.440 回答