【问题标题】:How to propagate event? InvalidStateError: Failed to execute 'dispatchEvent' on 'EventTarget': The event is already being dispatched如何传播事件? InvalidStateError:无法在“EventTarget”上执行“dispatchEvent”:事件已被调度
【发布时间】:2025-12-15 11:35:02
【问题描述】:

我正在尝试将我的 window.document 中的事件传播到此文档中的 iframe。

window.document 中捕捉事件时,我尝试以下操作:

event.preventDefault()
(@dispatchTo()).dispatchEvent(event)
# @dispatchTo() returns the reference of `document.querySelector('iframe').contentDocument`

但我得到InvalidStateError: Failed to execute 'dispatchEvent' on 'EventTarget': The event is already being dispatched.

我尝试了preventDefaultstopPropagation,但没有一个可以工作。当我尝试将事件分派到 iframe 文档时,似乎正在分派该事件,但它失败了。

如何在从window.document 捕获事件时将事件传播到我的 iframe?

该事件的 iframe 上确实有另一个 eventListener,但它没有被触发。

我使用 React(它有一个虚拟 DOM,它可能会干扰,也可能不会,只是说)。


我在那里找到了部分解决方案:https://*.com/a/20541207/2391795

现在我可以使用以下代码将事件从文档分派到 iframe:

eventClone = new event.constructor(event.type, event)
(@dispatchTo()).dispatchEvent(eventClone)

但是由于我使用的是 React,所以克隆的事件不等于初始事件,因为 React 有一种事件包装器。所以我丢失了很多属性,比如whichisTrusted,一旦克隆就变成了false

有什么方法可以正确克隆一个 React 事件?

【问题讨论】:

  • isTrusted 不是 React 的一部分,它是本机浏览器事件属性。您不能以编程方式创建事件并将 isTrusted 设置为 true

标签: javascript events reactjs


【解决方案1】:

当您尝试复制事件时,某些事件属性值会消失。这是因为许多事件属性的可枚举属性设置为 false:

Object.defineProperty(event, "target", {
    enumerable: false,
    writable: true,
});

这可以防止在克隆事件时复制属性的值。如果您尝试Object.keys(evt),则返回的唯一键是isTrusted

target 和 path 等一些属性只有在事件分发后才会设置,您不能手动分配它们。因此,如果您尝试调度已经有目标的事件,您将遇到错误InvalidStateError: Failed to execute 'dispatchEvent' on 'EventTarget': The event is already being dispatched

这就是您遇到此错误的原因。您试图分派一个已经分派的事件,而不是分派一个新事件。

所以当你创建你的事件时,你应该只复制你关心的属性:

 eventClone = new event.constructor(event.type, propertiesICareAbout) 

其中propertiesICareAbout 是一个包含您关心的事件部分的对象,例如propertiesICareAbout = {shiftKey: event.shiftKey}

isTrusted 是具有特定用途的属性——如果脚本与事件交互,则返回 false。正是出于这个原因,该属性设置为false。您正在使用脚本与事件交互并通过脚本调度它。 https://developer.mozilla.org/en-US/docs/Web/API/Event/isTrusted

which 属性已被弃用,并且正在被删除,因此无论如何您都不应该使用它。

React 事件可能与您的问题无关。出于性能原因,React 合成事件在顶层被委托和汇集。如果您手动调度事件,则应使用本机浏览器方法dispatchEvent

【讨论】: