Angular指令的this和闭包问题

huangapple go评论69阅读模式
英文:

Angular directive this and closure issue

问题

问题是在moveImage函数内部,this的上下文不正确,导致它根本不起作用。您犯了一个常见的错误,可以通过以下方式来修复它:

private moveImage = (e: MouseEvent): void => {
    let pos: { x: number; y: number }, x: number, y: number;
    e.preventDefault();
    /* 这里执行一些代码,也使用了 this.getPos(e) */
}

通过使用箭头函数来定义moveImage,您可以确保它在执行时保持正确的上下文,而不会丢失this的引用。这应该解决您遇到的问题。

英文:

I have such directive:

@Directive({
  selector: '[imgTest]',
})
export class ImgTest implements AfterViewInit, OnDestroy {

  private originalImage: HTMLImageElement;
  private secondImage: HTMLDivElement;

  constructor(private elementRef: ElementRef, public sanitizer: DomSanitizer) {}

  @HostListener('load')
  public onLoad(): void {
    this.process();
  }

  public ngAfterViewInit(): void {
    this.originalImage = this.elementRef.nativeElement;
  }

  public ngOnDestroy(): void {
    this.removeEventListeners();
  }

  private addEventListeners(): void {
    this.originalImage.addEventListener('mousemove', this.moveImage);
    this.secondImage.addEventListener('mousemove', this.moveImage);
  }

  private removeEventListeners(): void {
    this.originalImage.removeEventListener('mousemove', this.moveImage);
    this.secondImage.removeEventListener('mousemove', this.moveImage);
  }

  private process(): void {
    if (!this.originalImage) {
      return;
    }

    /* some magic */

    this.addEventListeners();
  }

  private moveImage(e: MouseEvent): void {
    let pos: { x: number; y: number }, x: number, y: number;
    e.preventDefault();
    /* some magic that is using also this.getPos(e) */
  }

  private getPos(e: MouseEvent): { x: number; y: number } {
    /* some magic */

    return { x: x, y: y };
  }
}

and the issue is that inside moveImage this is wrong and it's just not working at all.
what I've done wrong?

答案1

得分: 1

因为在addEventListener内部,this关键字不指向该类。您应该将代码修改为以下方式:

constructor(private elementRef: ElementRef, public sanitizer: DomSanitizer) {
  this.moveImage = this.moveImage.bind(this);
}

绑定了moveImage之后,它将按预期工作。

英文:

It's because inside the addEventListener, this keyword doesn't refer to the class. You should modify your code to the following:

  constructor(private elementRef: ElementRef, public sanitizer: DomSanitizer) {
    this.moveImage = this.moveImage.bind(this);
  }

After binding moveImage, it will work as expected

答案2

得分: 1

当您像这样添加监听器时

this.originalImage.addEventListener('mousemove', this.moveImage);

您基本上破坏了 "this" 引用。

为了保留正确的 "this" 引用,您可以以另一种方式添加监听器 - 您应该创建另一个回调函数,该回调函数会在正确的上下文中调用方法

this.originalImage.addEventListener('mousemove', (e) => this.moveImage(e));
// 或者
this.originalImage.addEventListener('mousemove', this.moveImage.bind(this));
// 或者
boundMoveImage = this.moveImage.bind(this) // 在类的某处内部
...
...addEventListener('mousemove', this.boundMoveImage); // 这样您可以在删除回调时删除事件监听器
英文:

when you are adding a listener like this

this.originalImage.addEventListener('mousemove', this.moveImage);

you are basically breaking "this" reference.

to preserve correct "this" it you could add a listener in an other way - you should create another callback which would call the method in the correct context

this.originalImage.addEventListener('mousemove', (e) => this.moveImage(e));
// or
this.originalImage.addEventListener('mousemove', this.moveImage.bind(this));
// or
boundMoveImage = this.moveImage.bind(this) // somewhere inside of a class
...
...addEventListener('mousemove', this.boundMoveImage); // this way you could removeEventListeners in remove callbacks

huangapple
  • 本文由 发表于 2023年7月13日 18:39:57
  • 转载请务必保留本文链接:https://go.coder-hub.com/76678440.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定