为什么事件冒泡在分离的 DOM 元素中不起作用?

Why doesn't event bubbling work in detached DOM elements?

我有一个 parent <div> 和一个 child <div> 在内存中 - 未附加到当前文档。我想在 child 上触发一个 CustomEvent,但从 parent 监听那个事件。这是我的代码:

var parent = document.createElement('div');
var child = document.createElement('div');
parent.appendChild(child);
parent.addEventListener('boom', function(event) {
    console.log('parent listener', event); // <~ This never runs!
});
var event = new CustomEvent('boom', { bubbles: true });
child.dispatchEvent(event);

此代码未按预期运行。 parent 上的事件侦听器永远不会触发。这似乎与 JavaScript 事件系统相矛盾,事件从目标中冒出来。但是,如果我将此代码段的最后两行修改为以下内容,回调将按照我的预期触发:

document.body.appendChild(parent);
child.dispatchEvent(event);

换句话说,如果我在分派事件之前将我的片段附加为文档的子树,那么 parent 事件侦听器将完全按预期触发。为什么?使用分离的 DOM 元素时有没有办法允许冒泡?

Why [doesn't bubbling work on detached elements]?

为了回答你的第一个问题,我查看了 W3C "UI Events (formerly DOM Level 3 Events)" spec, and didn't see anything that addressed this issue specifically. However, the event phase 部分,其中提到了一些让这种行为看起来合理的事情。

As the next step, the event object must complete one or more event phases. This specification defines three event phases: capture phase, target phase and bubble phase. Event objects complete these phases in the specified order using the partial propagation paths as defined below. A phase must be skipped if it is not supported, or if the event object's propagation has been stopped. For example, if the Event.bubbles attribute is set to false, the bubble phase will be skipped, and if Event.stopPropagation() has been called prior to the dispatch, all phases must be skipped.

强调我的。

规范接着列出了阶段:

  1. The capture phase: The event object must propagate through the target's ancestors from the Window to the target's parent. This phase is also known as the capturing phase. Event listeners registered for this phase must handle the event before it reaches its target.
  2. The target phase: The event object must arrive at the event object's event target. This phase is also known as the at-target phase. Event listeners registered for this phase must handle the event once it has reached its target. If the event type indicates that the event must not bubble, the event object must halt after completion of this phase.
  3. The bubble phase: The event object propagates through the target's ancestors in reverse order, starting with the target's parent and ending with the Window. This phase is also known as the bubbling phase. Event listeners registered for this phase must handle the event after it has reached its target.

再次强调我的。规范从不明确指出分离元素会发生什么。鉴于目标和冒泡阶段需要从元素到 window 的路径,并且在分离元素上没有可能的路径,因此必须跳过目标和冒泡事件阶段,因为这些路径不是支持。

Is there a way to allow bubbling when using detached DOM elements?

据我所知,没有任何允许冒泡的内置功能。您也许可以使用一些自定义代码来伪造冒泡,但这需要在每次触发事件时检查元素是否分离。

另一个想法是将元素添加到 DOM,触发事件,然后分离元素。由于我还没有测试过这个,我不知道它是否会起作用。