简体   繁体   English

指令在角度 6 外单击

[英]directive click outside angular 6

I upgraded my Angular from 4 to 6, and consequently had a problem with my click-off policy, it stopped working on all components.我将我的 Angular 从 4 升级到 6,因此我的点击策略出现问题,它停止在所有组件上工作。

my directive:我的指令:

import { Directive, Output, EventEmitter, ElementRef, HostListener } from '@angular/core';
    
@Directive({
  selector: '[clickOutside]'
})
export class ClickOutsideDirective {
    
  constructor(private _elementRef : ElementRef) { }
    
  @Output()
  public clickOutside = new EventEmitter();
   
  @HostListener('document:click', ['$event.target'])
  public onClick(targetElement) {
    const clickedInside = this._elementRef.nativeElement.contains(targetElement);
    if (!clickedInside) {
        this.clickOutside.emit(null);
    }
  }
}

My component.html that makes use of this directive:我的 component.html 使用了这个指令:

<div 
  id="sidenav" 
  *ngIf="this.opened" 
  class="sidenav" 
  [ngClass]="getClasses()" 
  [ngStyle]="getStyles()" 
  clickOutside 
  (clickOutside)="closeOutsideSidenav()"
>
  <header> {{ navTitle }} </header>
  <i 
    *ngIf="this.showCloseButton" 
    class="iconic iconic-x-thin close-icon" 
    (click)="closeSidenav()"
  ></i>
  <ng-content></ng-content>
</div>
<div 
  *ngIf="this.backdrop && this.opened" 
  class="sidenav-backdrop"
></div>

view:看法:

<div #insideElement></div>

component:成分:

export class SomeClass {
  @ViewChild("insideElement") insideElement;
  @HostListener('document:click', ['$event.target'])

  public onClick(targetElement) {
    const clickedInside = this.insideElement.nativeElement.contains(targetElement);
    if (!clickedInside) {
      console.log('outside clicked');
    }
  }
}

You're referencing "this" in your template, which is not necessary.您在模板中引用了“this” ,这是不必要的。 I made a working example of that directive:我做了一个该指令的工作示例:

https://stackblitz.com/edit/angular-piqewb https://stackblitz.com/edit/angular-piqewb

And theres no reason to have the directive on the div twice.并且没有理由在 div 上设置两次指令。

<div id="sidenav" *ngIf="opened" class="sidenav" [ngClass]="getClasses()" [ngStyle]="getStyles()" (clickOutside)="closeOutsideSidenav()">
    <header> {{ navTitle }} </header>
    <i *ngIf="showCloseButton" class="iconic iconic-x-thin close-icon" (click)="closeSidenav()"></i>
    <ng-content></ng-content>
</div>

<div *ngIf="backdrop && opened" class="sidenav-backdrop"></div>

This is a modification of @YoungHyeong Ryu answer above, but with unsubscription, so that the handler stops working when the component is unmounted.这是对上面@YoungHyeong Ryu 回答的修改,但取消订阅,以便在卸载组件时处理程序停止工作。

DEMO https://stackblitz.com/edit/angular-1q4pga演示https://stackblitz.com/edit/angular-1q4pga

import { Component, Input, OnInit, OnDestroy, ViewChild } from '@angular/core';

@Component({
  selector: 'app-click-outside',
  template: `<div #insideElement>Click outside me.</div>`
})
export class ClickOutsideComponent implements OnInit, OnDestroy  {
  @ViewChild('insideElement', { static: false }) insideElement;

  public ngOnInit() {
    this.onDocumentClick = this.onDocumentClick.bind(this);
    document.addEventListener('click', this.onDocumentClick);
  }

  public ngOnDestroy() {
    document.removeEventListener('click', this.onDocumentClick);
  }

  protected onDocumentClick(event: MouseEvent) {
    if (this.insideElement.nativeElement.contains(event.target)) {
      return;
    }
    console.log('Clicked outside!');
  }
}

Here, we remove the event listener on destroy.在这里,我们在销毁时删除事件侦听器。 Also, normally a method added by addEventListener is executed in a global context (instead of this context);另外,通常 addEventListener 添加的方法是在全局上下文(而不是this上下文)中执行的; so we should take care of it and bind onDocumentClick method to this (we do it in ngOnInit ).所以我们应该照顾它并将onDocumentClick方法绑定到this (我们在ngOnInit )。 Now we can use this inside onDocumentClick .现在我们可以在onDocumentClick使用this

Run the inside NgZone .运行内部NgZone

Example:例子:

export class AppComponent {
  opened: boolean = false;

  constructor(private ngZone: NgZone) {
  }

  closeOutsideSidenav(e) {
    this.ngZone.run(() => {
      this.opened = !this.opened;
    })
  }
}

I added my code to stackblitz.我将我的代码添加到 stackblitz。 https://stackblitz.com/edit/angular-gyhtym (click outside of the "Highlight Me!") https://stackblitz.com/edit/angular-gyhtym (在“突出显示我!”之外点击)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM