在有插槽问题的 Web 组件中使用事件委托(冒泡)

Using event delegation (bubbling) in web component with slot problem

我创建了这个简单的例子(纯 JS,不在 Vue 或 React 等中):

<body>
  <script>
    (function () {
      class MyComponent extends HTMLElement {
        constructor() {
          super();
          const shadowRoot = this.attachShadow({ mode: 'open' });
          const template = document.createElement('template');
          template.innerHTML = `
            <div>
              <button>
                <slot> <em>left</em> </slot>
              </button>
            </div>
          `;
          shadowRoot.append(template.content.cloneNode(true))

          shadowRoot.addEventListener('click', (event) => {
            // normal event delegation stuff,
            const button = event.target.closest('button');
            if (!button) return;
            // do somthing with button
            console.log(button);
          });
        }
      }

      customElements.define('my-component', MyComponent);
    }());
  </script>

  <my-component id="myComponent"></my-component>
</body>

目前效果很好

但是,插槽添加后:

<my-component id="myComponent"> <span>previous</span> </my-component>

事件委托代码坏了,因为我点击的是光 DOM 而不是影 DOM,所以,我用 const button = event.target.closest('button');

得到了 null

有什么建议可以在槽内使用事件委托吗?

如果语法有问题,我是中国人:) 感谢阅读

event.composedPath() 输出包含 click 事件通过的所有元素。
跨越其间的所有 shadowRoot 边界。

我把你的代码压缩了...

注意:SO 片段控制台速度慢且冗长;检查 TOP OF F12 控制台(SO 片段也可以在那里列出沙箱错误)

<script>
  customElements.define('my-component', 
   class extends HTMLElement {
    constructor() {
      super()
       .attachShadow({mode:'open'})
       .innerHTML = `<div>
                       <button><slot>Left</slot></button>
                     </div>`;
      this.shadowRoot.addEventListener('click', (evt) => {
        console.log(evt.composedPath());
      });
    }
  });
</script>

<my-component></my-component>
<my-component>Right</my-component>