You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

StencilJS中composed:false的自定义事件可在Shadow DOM外捕获的问题

为什么StencilJS中设置composed: false的自定义事件仍能在Shadow DOM外部被捕获?

我在StencilJS中使用@Event装饰器派发自定义事件,明确设置了{composed: false}(这也是默认值),按预期应该只能在Shadow DOM范围内监听该事件,但实际却能在Shadow DOM外部通过document.addEventListener捕获到它,有人能解释这种行为吗?


Stencil官方文档说明

composed?: boolean;
一个布尔值,指示事件是否可以跨越Shadow DOM和常规DOM之间的边界冒泡。


组件代码(component.tsx)

@Event() rate: EventEmitter<number>;

private handleStarClick(starIndex: number) {
    this.rate.emit(starIndex + 1);
}

页面代码(index.html)

<!DOCTYPE html>
<html dir="ltr" lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=5.0" />
    <link rel="stylesheet" href="/build/web-components.css" />
    <title>Stencil Component Starter</title>

    <script type="module" src="/build/web-components.esm.js"></script>
    <script nomodule src="/build/web-components.js"></script>

    <script type="module">
      document.querySelector("my-rating-stars").texts=["Terrible", "Bad", "Okay", "Good", "Excellent"];

      // 监听自定义事件
      document.addEventListener("rate", (e) => console.log(e))
    </script>
  </head>
  <body>
     <my-rating-stars></my-rating-stars>
  </body>
</html>

原因解析

问题出在StencilJS的@Event装饰器默认行为上:当你使用@Event()而不指定target时,事件默认是派发在组件本身(即自定义元素<my-rating-stars>),而非Shadow DOM内部的元素上。

因为事件的目标是属于常规DOM的自定义元素本身,所以即使设置了composed: false,事件也会在常规DOM的冒泡链中传播,自然能被document捕获到。composed属性控制的是事件是否能从Shadow DOM内部跨越到外部,而这里事件根本就没从Shadow DOM里派发出来,所以composed的设置不会影响它的传播范围。

如果想让事件只能在Shadow DOM内部被监听,需要修改@Event的配置,指定事件派发到Shadow DOM根节点,并确保composed: false:

@Event({ target: 'shadow', composed: false }) rate: EventEmitter<number>;

这样事件会被派发在组件的Shadow根上,由于composed: false,它无法跨越到常规DOM,此时只有在Shadow DOM内部添加的监听器才能捕获到这个事件。


内容的提问来源于stack exchange,提问作者saksonia

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 18:55:06