如何在外部点击时关闭下拉菜单? [英] How can I close a dropdown on click outside?

查看:27
本文介绍了如何在外部点击时关闭下拉菜单?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当用户点击该下拉菜单之外的任何地方时,我想关闭我的登录菜单下拉菜单,我想用 Angular2 和 Angular2方法"来做到这一点......

I would like to close my login menu dropdown when the user click anywhere outside of that dropdown, and I'd like to do that with Angular2 and with the Angular2 "approach"...

我已经实施了一个解决方案,但我真的对它没有信心.我认为必须有一种最简单的方法来实现相同的结果,所以如果您有任何想法......让我们讨论 :) !

I have implemented a solution, but I really do not feel confident with it. I think there must be an easiest way to achieve the same result, so if you have any ideas ... let's discuss :) !

这是我的实现:

这是我的下拉菜单的组件:

This is the component for my dropdown:

  • 每次将此组件设置为可见时,(例如:当用户单击按钮以显示它时)它订阅存储在 中的全局"rxjs 主题 userMenu主题服务.
  • 每次隐藏时,它都会取消订阅此主题.
  • 每次点击该组件模板的任何位置都会触发onClick()方法,该方法只会停止事件冒泡到顶部(和应用程序组件)
  • Every time this component it set to visible, (For example: when the user click on a button to display it) it subscribe to a "global" rxjs subject userMenu stored within the SubjectsService.
  • And every time it is hidden, it unsubscribe to this subject.
  • Every click anywhere within the template of this component trigger the onClick() method, which just stop event bubbling to the top (and the application component)

这是代码

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;
    }
}

应用组件:

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

The application component:

On the other hand, there is the application component (which is a parent of the dropdown component):

  • 该组件捕获每个点击事件并在同一个 rxjs 主题 (userMenu) 上发出

代码如下:

export class AppComponent {

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

什么困扰我:

  1. 让一个全局主题充当这些组件之间的连接器的想法让我感到非常不舒服.
  2. setTimeout:这是必需的,因为如果用户单击显示下拉菜单的按钮,否则会发生以下情况:
    • 用户单击按钮(不是下拉组件的一部分)以显示下拉列表.
    • 显示下拉菜单并立即订阅 userMenu 主题.
    • 点击事件冒泡到应用组件并被捕获
    • 应用程序组件在 userMenu 主题上发出事件
    • 下拉组件在 userMenu 上捕获此操作并隐藏下拉菜单.
    • 最后,下拉菜单永远不会显示.
  1. I do not feel really comfortable with the idea of having a global Subject that act as the connector between those components.
  2. The setTimeout: This is needed because here is what happen otherwise if the user click on the button that show the dropdown:
    • The user click on the button (which is not a part of the dropdown component) to show the dropdown.
    • The dropdown is displayed and it immediately subscribe to the userMenu subject.
    • The click event bubble up to the app component and gets caught
    • The application component emit an event on the userMenu subject
    • The dropdown component catch this action on userMenu and hide the dropdown.
    • At the end the dropdown is never displayed.

这个设置超时将订阅延迟到当前 JavaScript 代码轮的末尾,这解决了问题,但在我看来是一种非常优雅的方式.

This set timeout delay the subscription to the end of the current JavaScript code turn which solve the problem, but in a very in elegant way in my opinion.

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

If you know cleaner, better, smarter, faster or stronger solutions, please let me know :) !

推荐答案

你可以使用(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();
  }
}

另一种方法是创建自定义事件作为指令.查看 Ben Nadel 的这些帖子:

Another approach is to create custom event as a directive. Check out these posts by Ben Nadel:

这篇关于如何在外部点击时关闭下拉菜单?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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