【问题标题】:How to fix problem closing dropdown when I click outside it当我在外部单击时如何解决关闭下拉菜单的问题
【发布时间】:2019-07-04 19:58:18
【问题描述】:

我正在开发一个 Angular 5 项目。我的主页由许多组件组成。在navbarComponent 我有一个下拉列表。 当下拉列表打开时,在其外部单击时,我希望它自动关闭。

这是我的代码:

ngOnInit() {
    this.showMenu = false;
}

toggle() {
    this.showMenu = !this.showMenu;
}

<div *ngIf="isConnect" class=" userStyle dropdown-toggle " (click)="toggle()">
    <ul class="dropdown-menu subMenu" role="menu" *ngIf="showMenu">
        <li (click)="profile()" class="subMenuItem"> PROFILE</li>
        <li (click)="administration()" class="subMenuItem subMenuItem-last">ADMINISTRATION</li>
        <li class="subMenuItem subMenuItem-last"><button class="btn blue-btn" (click)="logout()" ><mat-icon mat-list-icon fontIcon="icon-logout"></mat-icon>LOGOUT</button></li>
    </ul>
</div>

【问题讨论】:

    标签: javascript angular typescript


    【解决方案1】:

    这就是我在项目中实现它的方式。首先我们需要在ngOnInit钩子中绑定窗口的点击事件。

    ngOnInit() : void {
      this.windowClickSubscription = Observable
        .fromEvent(window, "click")
        .subscribe(this.handleWindowClick)
    }
    

    现在只要点击窗口,我们的this.handleWindowClick就会被调用,让我们添加这个方法的实现。

    handleWindowClick(res: any) {
      let target: any = res.target;
      let threshold: number = 0;
      while(target && target.className != 'grouped-control' && threshold <= 4) {
        target = target.parentElement;
        threshold++;
      }
      if(target && target.className != 'grouped-control') this.hasOptions = false;
    }
    

    此函数将搜索事件目标的父级,直到找到grouped-control,当点击不包括此元素的窗口时,我们需要关闭它。因此,如果我们找到了该元素,我们什么也不做,我们使用hasOptions 标志关闭它。

    最后,我们需要在 ngDestroy 上取消绑定该事件

    ngOnDestroy(): void {
      this.windowClickSubscription && this.windowClickSubscription.unsubscribe();
    }
    

    现在你当然需要在你的组件中定义this.windowClickSubscription属性并将组件的引用绑定到你的构造函数中的函数handleWindowClick

    编辑

    要绑定构造函数的引用,请在构造函数中添加以下行

    constructor() {
      this.handleWindowClick = this.handleWindowClick.bind(this);
    }
    

    这将允许您将此函数作为回调处理程序传递,并将参考您的组件执行。

    由于我们可以在 *ngIf 的帮助下显示隐藏 html,因此我正在切换我需要使用标志 this. hasOptions 隐藏的控件

    【讨论】:

    • 我在handleWindowClick的构造函数中究竟做了什么?在 html 部分我做什么?
    【解决方案2】:

    当您打开 Dropdown 时,会添加任何类,例如 'open' 和类 'dropdown-toggle',当您关闭下拉列表时会删除该类。如果您在下拉区域之外单击,它将关闭下拉列表。

    我已经使用下面的代码实现了

    <div class="drop-menu">
        <a class="dropdown-toggle" title="Filter" (click)="openDropdown()">
           <span class="fa fa-arrow"></span>
        </a>
        <ul class="dropdown-menu subMenu" role="menu" *ngIf="showMenu">
           <li (click)="profile()" class="subMenuItem"> PROFILE</li>
           <li (click)="administration()" class="subMenuItem subMenuItem-last">ADMINISTRATION</li>
           <li class="subMenuItem subMenuItem-last"><button class="btn blue-btn" (click)="logout()" ><mat-icon mat-list-icon fontIcon="icon-logout"></mat-icon>LOGOUT</button></li>
        </ul>
    </div>
    

    component.ts 文件的代码:

    constructor(private renderer: Renderer2) { }
    ngOnInit() {
      const selectDOM = document.getElementsByClassName('dropdown-toggle')[0];
      this.renderer.listen('document', 'click', (evt) => {
        const eventPath = evt.path;
        const hasClass = _.where(eventPath, { className: 'drop-menu' });
        if (hasClass.length <= 0) {
          this.renderer.removeClass(selectDOM, 'open');
        }
      });
    }
    
    openDropdown() {
      const selectDOM = document.getElementsByClassName('dropdown-toggle')[0];
      if (selectDOM.classList.contains('open')) {
        this.renderer.removeClass(selectDOM, 'open');
      } else {
        this.renderer.addClass(selectDOM, 'open');
      }
    }
    

    【讨论】:

      【解决方案3】:

      在您的菜单中添加一个 TemplateRef-Id:

      <ul #menuRef class="dropdown-menu subMenu" role="menu" *ngIf="showMenu">
      
                      ....
      </ul>
      

      在代码中获取 TemplateRef:

      @ViewChild('menuRef') menuRef: TemplateRef<any>;
      

      然后你必须注册一个全局(在文档级别)点击事件:

      @HostListener('document:click', ['$event'])
      hideMenu(event) {
        if (!this.menuRef.nativeElement.Contains(event.target) {
          if (this.showMenu) {
             this.showMenu = false;
          }
        }
      }
      

      如果点击在您的下拉菜单之外,您设置 showMenu=false 并关闭您的菜单。

      但是为什么不使用一个组件作为你的下拉菜单呢? ng-select 自动完成所有这些操作。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-03-23
        • 2023-02-23
        • 1970-01-01
        • 2016-06-13
        • 1970-01-01
        • 1970-01-01
        • 2021-09-01
        相关资源
        最近更新 更多