如何检查事件目标是否在一个元素内?

时间:2018-05-08 09:49:39

标签: angular dom-events

我有“Card”组件正在侦听外部点击或滚动事件,并在发生此事件时被销毁。

@HostListener('document:mousedown', ['$event'])
public onEvent(e: Event): void {
    let el = this.elementRef.nativeElement;
    if (e.target !== el && !el.contains(e.target)) {
        this.destroyCard();
    }
}

ngAfterViewInit() {
  document.addEventListener('scroll', this.onEvent, true);
}

问题来自于此组件我创建模态窗口,该窗口在应用程序视图根目录中的此组件外部创建。当我点击模态窗口或滚动它时,我的卡片组件会随着模态窗口一起被销毁。

这是沙箱stackblitz with click。 当你点击模态窗口时,它应该保持不变。

已更新即可。修复了event.stopPropagation()。

但它不适用于通常不像滚动的泡沫这样的事件。请参阅stackblitz with scroll

我只看到一个解决方案:创建将侦听事件的服务,我的Card组件和Modal窗口组件将订阅并将它们添加到数组中,将检查事件目标是否放置在此节点内。

也许有人知道更好的解决方案?

1 个答案:

答案 0 :(得分:2)

您可以处理模态组件中的mousedown事件,并调用event.stopPropagation()以确保它未达到document级别。您可以在this stackblitz中看到结果。

export class ModalWindowComponent {
    @HostListener('mousedown', ['$event'])
    public processMouseDown(event: MouseEvent): void {
        event.stopPropagation();
    }
}

重要:请务必致电event.stopPropagation(),而不是event.stopImmediatePropagation()

  • event.stopPropagation()可防止事件冒泡到元素的祖先(参见MDN documentation
  • event.stopImmediatePropagation()只是阻止调用元素上的其余侦听器(参见MDN documentation

对于滚动事件,调用event.stopPropagation不起作用。如果滚动元素具有特定属性,则可以保持模态打开,例如data-keepmodalopen="true"(小写)。以下是此类检查的代码(有关演示,请参阅 this stackblitz ):

<div class="container">Modal window. I should stay
  <div class="scroll-container" data-keepmodalopen="true">
    ...
  </div>
</div>
public onScroll(e: MouseEvent): void {
  if (this.window && !this.keepModelOpen(e.target as HTMLElement)) {
    this.window.destroy();
    this.window = null;
  }
}

public keepModelOpen(element: HTMLElement): boolean {
  return element.dataset.keepmodalopen === "true";
}