在Angular 4中使用指令检测元素外的点击

21

我在Angular 2中使用自定义指令来检测元素外的点击,但在Angular 4中不可能使用同样的方式。

[plunkr] https://plnkr.co/edit/aKcZVQ?p=info

当我尝试在angular-4中使用相同的代码时,会出现以下错误:

1. Argument of type '{ template: string; directives: typeof ClickOutside[]; }' is not assignable to parameter of type 'Component'. ==> 

    @Component({
    templateUrl: "",
    directives: [ClickOutside]
    })


2. Type 'Subscription' is not assignable to type 'Observable<MouseEvent>'. in the directive inside ngOnInit() and ngOnDestroy() 

ngOnInit() {
    this.globalClick = Observable
        .fromEvent(document, 'click')
        .delay(1)
        .do(() => {
            this.listening = true;
         }).subscribe((event:MouseEvent) => {
            this.onGlobalClick(event);
         });
}

ngOnDestroy() {
    this.globalClick.unsubscribe();
}

如果在 Angular 4 的指令声明中有任何更改,请告诉我,官方文档对此没有帮助。


抱歉,这个:https://dev59.com/66Tja4cB1Zd3GeqPHtHT#45997092 - Vega
@Vega 我正在使用相同的方法,但唯一的问题是应用程序需要2000毫秒的时间来处理每次点击,这很糟糕,因为这会扭曲用户体验。 - Ronit Oommen
此外,ng-click-outside 节点包似乎可以用于此目的。看起来甚至可以与最新的 Angular 版本(目前为 Angular 6+)一起使用。(将此评论视为仅供参考的评论) - Deadpool
1个回答

50

关于你的plnkr,有一些变化。

  1. NgModules,或者看一下框架的架构。模块是你应该注册组件、服务和指令的地方。
  2. 一旦你在模块中注册了你的指令,你就不必在组件中导入它。

对我来说,这个指令本身看起来很好。我将你的指令与我在Angular 4.3.5中运行良好的指令进行了比较。

实际上,在这种情况下,你不需要任何指令,除非它不会被重复使用。如果你需要将clickOutside应用于菜单,最好这样做:

将click事件绑定到你的“inside”选择器上,就像这样。假设它是你的菜单:

  <ul id="menu" (click)="clickedInside($event)"> <li> .. </li> </ul>

然后在您的组件内添加以下clickedInside()函数:

  clickedInside($event: Event){
    $event.preventDefault();
    $event.stopPropagation();  // <- that will stop propagation on lower layers
    console.log("CLICKED INSIDE, MENU WON'T HIDE");
  }

最后,您可以在组件中使用Host Listener将单击绑定到文档的其余部分

  @HostListener('document:click', ['$event']) clickedOutside($event){
    // here you can hide your menu
    console.log("CLICKED OUTSIDE");
  }

这里有一个最小化的工作演示:plnkr - Kuba
即使我停止将延迟传递到较低的元素,菜单关闭时间仍为2300毫秒,这似乎是一个错误,但是它确实有效。 - Ronit Oommen
如果你隐藏的区域是一个拖放区域,会怎样呢?当我点击它时,“选择文件窗口”会打开,但是 clickedInside() 没有被调用。我该如何缩小范围? - tatsu
回答自己:那么你会想要非常具体地测试事件,希望组件在其元素和类名称方面非常独特:将此作为取消选择的 if 条件之一:!$event.path[0].classList[0].startsWith('dz') - tatsu

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接