覆盖typescript类

时间:2017-06-06 17:37:34

标签: javascript typescript

我在打字稿中创建了这个按钮类。我给了它一个"默认"处理点击事件的功能。但是如果我想要将一个函数作为参数传递并在点击时调用传递的函数呢?

这里是代码:

abstract class BaseButton {

  element:HTMLElement;
  label:string;

  constructor(element:HTMLElement, label:string) {
    console.log(this);
    this.element = element;
    this.label = label;
    this.init();
  }

  init():void {
    this.setText(this.label);
    this.addListeners();
  }

  setText(label:string):void {
    this.element.innerHTML = label;
  }

  kill():void {
    this.removeListeners();
  }

  addListeners():void {
    this.element.addEventListener("mouseover", this.onMouseOver);
    this.element.addEventListener("click", this.onClick);
    this.element.addEventListener("mouseout", this.onMouseOut);
    this.element.addEventListener('touchstart', this.onTouchStart);
    this.element.addEventListener('touchmove', this.onTouchMove);
    this.element.addEventListener('touchcancel', this.onTouchCancel);
    this.element.addEventListener('touchend', this.onTouchEnd);
  }

  removeListeners():void {
    this.element.removeEventListener("mouseover", this.onMouseOver);
    this.element.removeEventListener("click", this.onClick);
    this.element.removeEventListener("mouseout", this.onMouseOut);
    this.element.removeEventListener('touchstart', this.onTouchStart);
    this.element.removeEventListener('touchmove', this.onTouchMove);
    this.element.removeEventListener('touchcancel', this.onTouchCancel);
    this.element.removeEventListener('touchend', this.onTouchEnd);
  }

  onTouchStart():void {

  }

  onTouchMove():void {

  }

  onTouchCancel():void {

  }

  onTouchEnd():void {

  }

  onMouseOver():void {
    console.log('mouse over');
  }

  onMouseOut():void {
    console.log('mouse out');
  }

  abstract onClick(event:Event):void
}

class Button extends BaseButton {

  element:HTMLElement;
  label:string;
  callback:any;

  constructor(element:HTMLElement, label:string, callback?: () => void) {
    super(element,label);
    this.element = element;
    this.label = label;
    this.callback = callback;
  }

  onClick(event:Event):void {
    if (this.callback) {
      console.log('ddd');
      this.callback();
    }
  }  
}





const el = document.getElementById('btn');
const button = new Button(el,'Click');

const ell = document.getElementById('btnn');
const buttonn = new Button(ell,'Click');

const elll = document.getElementById('btnnn');
const buttonnn = new Button(elll,'Click', () => {
  alert('fff');
});

2 个答案:

答案 0 :(得分:0)

当以下事件处理程序在基类中运行时,您正在丢失子类的this函数内的onClick引用:

this.element.addEventListener("click", this.onClick) 

通常可以使用箭头函数来解决这个问题:

class Button extends BaseButton {
  constructor(element: HTMLElement, label: string, private callback?: () => void) {
    super(element, label);
  }

  onClick = (event: Event) => {
    if (this.callback) {
      this.callback();
    }
  }
}

但在这种特殊情况下,如果您尝试在子类中定义它,则会出现以下错误:

  

Class'BaseButton'定义实例成员函数'onClick',但是   扩展类'Button'将其定义为实例成员属性。

如果您尝试在子类的构造函数中定义onClick箭头函数:

class Button extends BaseButton {
  constructor(element: HTMLElement, label: string, private callback?: () => void) {
    super(element, label);

    this.onClick = () => {
      // ...
    }
  }
}

您将收到以下错误:

  

非抽象类'Button'不实现继承的抽象   来自'BaseButton'课程的成员'onClick'

如果你试图创建一个存根方法只是为了让错误消失,并在构造函数中创建一个真正的方法作为箭头函数:

class Button extends BaseButton {
  constructor(element: HTMLElement, label: string, private callback?: () => void) {
    super(element, label);

    this.onClick = () => {
      // ...
    }
  }

  onClick(event: Event) { }
}

它不起作用,因为基类会将错误的onClick函数引用传递给addEventListener,因为该代码在子类的构造函数之前运行。

这是一个解决方法。通过创建一个调用this的单独函数在基类中绑定this.onClick(),并保留对该新函数的引用,以便您可以取消注册它。

abstract class BaseButton {
  private onClickBound;

  constructor(protected element: HTMLElement, protected label: string) {
    this.init();
  }

  init(): void {
    this.addListeners();
  }

  kill(): void {
    this.removeListeners();
  }

  addListeners(): void {
    this.onClickBound = (e: Event) => this.onClick(e);

    // Or you can do this:
    // this.onClickBound = this.onClick.bind(this)

    this.element.addEventListener("click", this.onClickBound);
  }

  removeListeners(): void {
    this.element.removeEventListener("click", this.onClickBound);
  }

  abstract onClick(event: Event);
}

class Button extends BaseButton {
  constructor(element: HTMLElement, label: string, private callback?: () => void) {
    super(element, label);
  }

  onClick(event: Event) {
    if (this.callback) {
      this.callback();
    }
  }
}

我会尝试提出一个更清洁的解决方案,因为我对此并不感到疯狂。

答案 1 :(得分:0)

如果您执行了类似的操作(添加了其余代码),该怎么办?

class Button {
    clickListener; // with any types

    constructor(clickListener = defaultClickListener) {
        this.clickListener = clickListener;
        this.clickListener();
    }
}

function defaultClickListener():void {
    console.log(0);
}

new Button(() => console.log(1));