这个问题一直让我抓狂。我有两个组件,它们都是同一页面上的可切换下拉菜单。我对这两个组件都有类似的东西:
@HostListener('click', ['$event'])
clickInside() {
event.stopPropagation();
this.showMenu = true;
}
@HostListener('document:click')
clickOutside() {
if (this.showMenu) {
this.showMenu = false;
}
}
它对于一个组件来说效果很好,但是当我在同一页面上有两个组件时,单击另一个组件将使第一个组件保持打开状态,结果是它们同时打开,这是我不希望的。原因当然是 event.stopPropagation(),但如果没有这个,组件内的点击也将是文档内的点击。
最佳答案
当我们单击组件内部时 - 它应该打开,当单击外部时 - 它应该关闭。
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 之外的事件,但更改内部的状态。
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();
}
关于javascript - 在 Angular 中使用单击事件处理多个组件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52108773/