小编典典

如何关闭外部点击的下拉菜单?

javascript

当用户单击下拉菜单之外的任何地方时,我想关闭我的登录菜单下拉菜单,我想使用Angular2和Angular2“方法”来完成此操作…

我已经实现了一个解决方案,但是我对此确实没有信心。我认为必须有一种最简单的方法来达到相同的结果,因此,如果您有任何想法…让我们讨论一下:)!

这是我的实现:

下拉组件:

这是我的下拉菜单的组成部分:

  • 每次将此组件设置为可见时,(例如:当用户单击按钮以显示它时)它将订阅存储在 SubjectsService中 的“全局” rxjs主题 userMenu 。 __
  • 每次隐藏时,它都会退订该主题。
  • 该组件模板 任何位置的每次点击都会触发 onClick() 方法,该方法只会停止将事件冒泡到顶部(和应用程序组件)

这是代码

export class UserMenuComponent {

    _isVisible: boolean = false;
    _subscriptions: Subscription<any> = null;

    constructor(public subjects: SubjectsService) {
    }

    onClick(event) {
        event.stopPropagation();
    }

    set isVisible(v) {
        if( v ){
            setTimeout( () => {
this._subscriptions =  this.subjects.userMenu.subscribe((e) => {
                       this.isVisible = false;
                       })
            }, 0);
        } else {
            this._subscriptions.unsubscribe();
        }
        this._isVisible = v;
    }

    get isVisible() {
        return this._isVisible;
    }
}

应用程序组件:

另一方面,存在应用程序组件(它是下拉组件的父级):

  • 该组件捕获每个click事件并在相同的rxjs Subject( userMenu )上发出

这是代码:

export class AppComponent {

    constructor( public subjects: SubjectsService) {
        document.addEventListener('click', () => this.onClick());
    }
    onClick( ) {
        this.subjects.userMenu.next({});
    }
}

什么困扰我:

  1. 我对于让全局主题充当这些组件之间的连接器的想法感到非常不满意。
  2. setTimeout的 :这是必要的,因为这里是,如果在此按钮,用户点击,显示的下拉什么,否则会发生:
    • 用户单击按钮(不是下拉菜单组件的一部分)以显示下拉菜单。
    • 显示该下拉菜单, 它立即订阅userMenu主题
    • 点击事件冒泡到应用程序组件并被捕获
    • 应用程序组件在 userMenu 主题上发出事件
    • 下拉组件在 userMenu 上捕获此操作,并隐藏下拉菜单。
    • 最后,从不显示下拉列表。

这个设置的超时将订阅延迟到当前JavaScript代码回合的结尾,从而解决了问题,但是我认为这是一种非常优雅的方式。

如果您知道更清洁,更好,更智能,更快或更强大的解决方案,请告诉我:)!


阅读 319

收藏
2020-05-01

共1个答案

小编典典

您可以使用(document:click)事件:

@Component({
  host: {
    '(document:click)': 'onClick($event)',
  },
})
class SomeComponent() {
  constructor(private _eref: ElementRef) { }

  onClick(event) {
   if (!this._eref.nativeElement.contains(event.target)) // or some similar check
     doSomething();
  }
}
2020-05-01