仅在外部点击时调用函数无法按预期工作

only calling function on outside click not works as expected

在我的 angular 指令中,单击主机元素时会显示弹出窗口。当弹出窗口打开状态时,如果用户在任何地方点击外部,我需要关闭弹出窗口。为此,我尝试使用以下代码。但不起作用。 this.removeComponent(); 方法总是调用。

@HostListener("window:mouseup", ["$event"]) clickedOut(event) {
if (event.target.nativeElement === this.hostElement) {
  //when click on host element do nothing!
  return;
}
//when click outside otherthan this.hostElement remove the componenet
this.removeComponent();
}

任何人都可以帮助我处理这种情况吗?

这应该可以解决您的问题,问题的发生是因为您正在将一个元素与一个元素数组进行比较,而元素数组始终为 false,从而给您带来错误。

@HostListener("window:mouseup", ["$event"]) clickedOut(event) {
    if (this.hostElement.nativeElement.contains(event.target)) {
      //when click on host element do nothing!
      return;
    }
    else{
    this.removeComponent();
    }
    //when click outside other than this.hostElement remove the component
    }

应该是

  @HostListener('window:mouseup', ['$event']) clickedOut(event) {

    //you looking for "event.target" into "this.element.nativeElement"

    if (!this.elementRef.nativeElement.contains(event.target)) {
      console.log("outside")
    }
    else
    {
      console.log("inside")
 
    }
  }

注意:如果您不希望传播元素上的点击,请在 HostListener(点击)中使用 event.stopPropagation();

   @HostListener('click', ['$event']) onClick(event) {
    ....
    event.stopPropagation(); //<---this line
  }

或者完全删除它,只使用大约 window:mouseup

的 hostListener

stackblitz(仅在控制台点击外侧和点击内侧显示)

更新 使用此方法,您会得到如此多的“点击外部”元素以及您拥有的指令

如果我们的目标是显示弹出窗口或类似窗口,那也没有问题,因为通常我们当时没有太多元素。但是想象一下我们的指令只是放置一个边框——例如——。我们应该采取另一种方法。首先我们可以使用 HostBinding,所以我们的指令只能管理创建一个边框。看到我们将 elementRef 注入为“public”

@Directive({
  selector: '[showpop]'
})
export class ShowPopDirective {
  border: boolean=false;
  constructor( public elementRef: ElementRef ) {}

  @HostBinding('style.border') get _(){return this.border?'1px solid red':null}
  
}

而且我们可以从外部组件控制外部

  @ViewChildren(ShowPopDirective) items:QueryList<ShowPopDirective>
  @HostListener('window:mouseup', ['$event']) clickedOut(event) {
    this.items.forEach(x=>{
      x.border=!x.border && x.elementRef.nativeElement.contains(event.target)
    })
  }

stackblitz