如何从具有多个影子 DOM 的 Web 组件内部创建全局点击监听器?

How to create a global click-listener from inside a web-component with multiple shadow DOMs?

我用 lit-element 和 Typescript 构建了一个网络组件。它包括一个下拉列表,如果用户单击页面上的其他任何地方,我想将其关闭。拥有全局点击监听器很简单:

window.addEventListener('click', e => this.globalClickHandler(e), false)

但在 globalClickHandler 内部,我需要区分组件内部和外部的点击 - 我该如何实现?我不能使用 event-target 因为它只会给我最顶层的影子根。

我希望这对某人有所帮助,因为我确实花了几个小时才找到答案。

解决方案:

globalClickHandler(event) {
  if (!event.composedPath().includes(this)) {
    // this.open = false or whatever floats your boat
  }
}

解释:

通常你会做类似 this.contains(event.target) 的事情,但这对我们不起作用,因为我们的 EventTarget isn't the actual element that was clicked and our this's only child is a ShadowRoot. Luckily event.composedPath() 是为了缓解这种情况而创建的:

The composedPath() method of the Event interface returns the event’s path which is an array of the objects on which listeners will be invoked.

所以 composedPath 基本上是我们的事件经过的所有元素的列表,同时忽略了影子 DOM。这意味着我们所要做的就是遍历我们获得的元素数组并检查我们的元素 (this) 是否包含在内。