Angular 5 自定义指令触发包装到 *ngIf=false 中的元素

Posted

技术标签:

【中文标题】Angular 5 自定义指令触发包装到 *ngIf=false 中的元素【英文标题】:Angular 5 custom directive fires for element wrapped into *ngIf=false 【发布时间】:2019-01-27 13:07:19 【问题描述】:

我正在研究应该在点击外部后关闭下拉菜单的指令。具有指令的元素也有*ngIf 并且在单击时不存在于页面上,但指令仍在触发事件 - 所以下拉菜单永远不会打开,因为showList(click)="showList = true" 之后立即变为false被解雇了。我该如何避免这种情况?

stackblitz

import  Directive, HostListener, ElementRef, EventEmitter, Inject, PLATFORM_ID, Output, Input, OnInit, Renderer2, AfterContentInit  from '@angular/core';
import  isPlatformBrowser  from '@angular/common';

@Directive(
  selector: '[clickOutside]'
)
export class ClickOutsideDirective implements AfterContentInit 

  ngAfterContentInit(): void 
    this.contentInitialized = true;
  
  @Input("clickOutside") config: any = ;
  @Output() clickOutside: EventEmitter<any> = new EventEmitter();
  private isBrowser: boolean = false;
  private isIE11: boolean = false;
  private contentInitialized: boolean = false;

  constructor(private renderer: Renderer2, private _el: ElementRef, @Inject(PLATFORM_ID) private platformId: any) 
    this.isBrowser = isPlatformBrowser(platformId);
    this.isIE11 = this.isBrowser && !!(window as any).MSInputMethodContext && !!(document as any).documentMode;
  

  @HostListener('document:click', ['$event'])
  public onClick(event) 
    console.log("CLICKED");
    if (this.contentInitialized && !(this._el.nativeElement.contains(event.target) || (event.target == window.document.querySelector(this.config.excludeLocator)))) 
      this.clickOutside.emit(event);
    
  

  @HostListener('document:keyup', ['$event'])
  private onKeyup(event) 
    if (event.keyCode == 27) 
      this.clickOutside.emit(event);
    
  

<div class="menu-trigger" (click)="showList = true"></div>
<ul class="list" *ngIf="showList" (clickOutside)="showGiftList = false">
  <li>item 1</li>
  <li>item 2</li>
  <li>item 3</li>
  <li>item 4</li>
</ul>

【问题讨论】:

您的 html 不会在任何地方使用 clickOutside。在 StackBlitz 中发布一个完整的最小示例,重现问题。 你试过$event.stopPropagation();吗? @JBNizet 是的,错过了,这里是 stackblitz stackblitz.com/edit/… @NasiruddinSaiyed 你想在.menu-trigger 上看到那个吗?似乎在工作stackblitz.com/edit/… 是的,它应该停止事件。 【参考方案1】:

为了避免父事件运行,您需要从子元素中停止它,您可以通过

$event.stopPropagation();

event.stopPropagation() 方法停止冒泡事件 父元素,防止任何父事件处理程序 执行。

如果您想学习一些基础知识并了解更多HTML 事件,您可以查看this。

【讨论】:

你知道从 Angular 的角度来看 - 为什么当 *ngIf=flase 时它会被解雇?我认为如果元素不在 dom 中,它不应该接受任何交互 此时它实际上在 DOM 中。 1. 页面加载 - 不在 DOM 中 2. 点击触发器设置 showList = true --> 在 DOM 中 3. 事件冒泡 4. 触发主机监听器 5. showList = false --> 不再在 DOM 中

以上是关于Angular 5 自定义指令触发包装到 *ngIf=false 中的元素的主要内容,如果未能解决你的问题,请参考以下文章

下拉菜单的角度 6 自定义指令不起作用

vue自定义指令,包装函数节流。

如果使用 *ngIf 删除子组件,则会触发 Angular 自定义 clickaway 侦听器

在Angular2中将自定义指令绑定到Observable

需要访问 Angular 5 指令文本

angular的自定义指令---详解