【问题标题】:only calling function on outside click not works as expected仅在外部单击时调用函数不能按预期工作
【发布时间】:2025-11-22 19:55:02
【问题描述】:

在我的角度指令中,单击主机元素时会弹出显示。当弹出窗口打开状态时,如果用户在任何地方点击外部,我需要关闭弹出窗口。为此,我尝试使用以下代码。但不起作用。 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();
}

有人请帮我处理这种情况吗?

【问题讨论】:

标签: angular angular-directive


【解决方案1】:

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

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

【讨论】:

  • 收到错误为:Cannot read property 'contains' of undefined
  • 已编辑答案,请检查
【解决方案2】:

应该是

  @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(仅显示在控制台点击外部和点击内部)

更新用这种方法,你会得到很多“点击外部”作为你有指令的元素

如果我们的 dfirective 是显示一个弹出窗口或类似的,没有问题,因为我们通常没有很多元素。但是想象一下,我们的指令只是设置一个边框——例如——。我们应该采取另一种方法。首先我们可以使用 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

【讨论】:

  • 你能在这里更新吗:stackblitz.com/edit/…
  • 用你的分叉堆栈闪电战更新答案
  • 需要一个小建议,当我实现这段代码时,我得到了 13 次安慰 onclick,这是什么问题?我正在使用 angular8,对于你来说,在 stackblitz 中它只能控制台一次
  • 您将获得如此多的“点击外部”作为您拥有的指令的元素。尝试重新启动应用程序(或刷新导航器)。顺便说一句,我更新了答案以使用 ViewChildren 控制一系列指令-但我认为这不是您的情况-。另一个建议是使用 rxjs 运算符 fromEvent-dont' forget unsubscribe- 代替 HostListener,但我认为 hostListener 应该是正确的
  • 感谢您的回答。虽然我发现了一个问题,但更新了屏幕截图。当我单击单选按钮时,弹出窗口会关闭。没有功能触发器。它认为我在外面点击。我尝试添加传播但没有运气。请问有什么帮助吗?