在Angular中使用单击事件处理多个组件 [英] Handling multiple components with click events in Angular

查看:60
本文介绍了在Angular中使用单击事件处理多个组件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这个问题使我发疯.我有两个组件,它们都是同一页面上的可切换下拉菜单.对于这两个组件,我都有类似的东西:

This problem has been driving me nuts. I have two components which both are toggleable dropdowns on the same page. I have something like this for both components:

@HostListener('click', ['$event'])
clickInside() {
  event.stopPropagation();
  this.showMenu = true;
}

@HostListener('document:click')
clickOutside() {
  if (this.showMenu) {
    this.showMenu = false;
  }
}

对于一个组件来说它工作得很好,但是当我在同一页面上有两个组件时,单击另一个组件将使第一个组件处于打开状态,结果是它们都同时在我不希望的状态下打开.原因当然是 event.stopPropagation(),但没有此原因,在组件内部单击也将是在文档内部单击.

It works just fine for one component but when I have two components on the same page then clicking the other component will leave the first component open and the result is that they are both open at the same time which I do not want. The reason is of course the event.stopPropagation() but without this, a click inside the component will also be a click inside the document.

推荐答案

当我们在内部组件中单击时-应该将其打开,在外部单击时应将其关闭.

When we click inside component - it should be opened, when click was outside - it should be closed.

  constructor(private elementRef: ElementRef){}

  @HostListener('click')
  clickInside() {
    this.showMenu = true;
  }

  @HostListener('document:click', ['$event'])
  clickOutside(event) {
    if (this.showMenu && this.isClickOutside(event)) {
      this.showMenu = false;
    }
  }

  private isClickOutside(event: MouseEvent): boolean {
    return !this.elementRef.nativeElement.contains(event.target);
  }

此解决方案至少具有一个缺点-文档上带有侦听器的每个组件都将导致附加更改检测周期.为了防止这种情况,我们应该在angular之外处理事件,但在内部更改状态.

This solution have at least one disadvantage - each component with listener on document will lead to addition change detection cycle. To prevent this we should handle event outside of angular but change the state inside.

private readonly onDestroy$ = new Subject();

constructor( private ngZone: NgZone,) {}

ngOnInit() {
    this.ngZone.runOutsideAngular(() => {
      fromEvent(window.document, 'click')
        .pipe(
          filter(
            (event: MouseEvent) =>
              this.isOpen() && this.isClickOutside(event)
          ),
          takeUntil(this.onDestroy$),
        )
        .subscribe(() => {
          this.ngZone.run(() => {
            this.close();
          });
        });
    });
  }

ngOnDestroy() {
    this.onDestroy$.next();
    this.onDestroy$.complete();
  }

这篇关于在Angular中使用单击事件处理多个组件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆