【问题标题】:Why doesn't event bubbling work in detached DOM elements?为什么事件冒泡在分离的 DOM 元素中不起作用?
【发布时间】:2015-06-17 11:46:54
【问题描述】:

我有一个父母 <div> 和一个孩子 <div> 在内存中 - 未附加到当前文档。我想在孩子身上触发CustomEvent,但要听来自父母的那个事件。这是我的代码:

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);

此代码未按预期工作。父级上的事件侦听器永远不会触发。这似乎与 JavaScript 事件系统的矛盾,即事件从目标冒泡。但是,如果我将此 sn-p 的最后两行修改为以下内容,回调将按我的预期触发:

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

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

【问题讨论】:

  • 我在这里看不到任何虚拟 DOM,虚拟 DOM 通常意味着不是真正的 DOM 的 DOM - 你的 DOM 是非常真实的,只是分离的。
  • 另外,这里有一个解决方案medium.com/@webprolific/…,如果这解决了您的问题,请为未来的访问者写一个答案:)
  • @RobG 是文档对象模型,它代表了你如何通过一个对象API与文档交互,一个有子元素的元素肯定是一个指定与文档交互的对象,而文档更多不仅仅是dom树。 AJAX 等也是 DOM API 的一部分,webworkers 也是如此。
  • 好的,修改了标题。虽然……在实践中,“虚拟 DOM”不是经常简单地通俗地用来表示分离的 DOM 元素吗?
  • @BenjaminGruenbaum——应该在某处放一个幽默的表情……

标签: javascript google-chrome dom javascript-events


【解决方案1】:

为什么[冒泡对分离的元素不起作用]?

为了回答您的第一个问题,我查看了W3C "UI Events (formerly DOM Level 3 Events)" spec,并没有看到任何专门解决此问题的内容。但是,event phase 部分提到了一些使这种行为看起来合理的事情。

作为下一步,事件对象必须完成一个或多个事件阶段。本规范定义了三个事件阶段:捕获阶段、目标阶段和冒泡阶段。事件对象使用如下定义的部分传播路径以指定的顺序完成这些阶段。 如果不支持某个阶段,则必须跳过该阶段,或者如果事件对象的传播已停止。例如,如果 Event.bubbles 属性设置为 false,则将跳过气泡阶段,如果在调度之前已调用 Event.stopPropagation(),则必须跳过所有阶段。

强调我的。

然后规范继续列出阶段:

  1. 捕获阶段事件对象必须通过目标的祖先从窗口传播到目标的父项。此阶段也称为捕获阶段。为此阶段注册的事件侦听器必须在事件到达其目标之前对其进行处理。
  2. 目标阶段:事件对象必须到达事件对象的事件目标。此阶段也称为目标阶段。为该阶段注册的事件侦听器必须在事件到达其目标后对其进行处理。如果事件类型指示事件不能冒泡,则事件对象必须在此阶段完成后停止。
  3. 冒泡阶段事件对象以相反的顺序通过目标的祖先传播,从目标的父级开始,以窗口结束。此阶段也称为冒泡阶段。为此阶段注册的事件侦听器必须在事件到达其目标后对其进行处理。

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

有没有办法在使用分离的 DOM 元素时允许冒泡?

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

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

【讨论】:

  • 我的猜测是该短语只是为了使不支持捕获阶段的 IE 兼容。
  • 这是一个很好的答案,我同意尽管规范没有明确说明这种情况下的行为,但它不会发生确实是有道理的。无论如何,“手动”实现事件冒泡非常简单:只需将事件对象分派给每个parentNode,从所需目标开始并遍历到分离树的顶部。
  • @GladstoneKeep,看起来很简单,但您仍然必须记住为事件分配正确的 targetcurrentTarget 属性。对我来说,支持似乎需要很多开销。
猜你喜欢
  • 2013-10-22
  • 2017-02-14
  • 1970-01-01
  • 2023-03-12
  • 1970-01-01
  • 2023-03-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多