问题
In JavaScript, for an event handler that needs access to private members and functions, I can rely on the function scope of those to be accessible within my event handler function, and do something like this:
theElement.addEventListener("click", onClick);
and later:
theElement.removeEventListener("click", onClick);
In TypeScript, I need to use an anonymous function to have this be the containing object, like so:
theElement.addEventListener("click", (event) => this.onClick(event));
In this case, I can't remove the anonymous function from the listening to the event. How do I have an event listener as part of a class (with access to private fields and methods), that I can remove later?
回答1:
First, JavaScript and TypeScript behave the exact same way even if you write like that:
theElement.addEventListener("click", onClick);
Second, this is how you can retain a reference to an anonymous function:
var f = (event) => this.onClick(event);
theElement.addEventListener("click", f);
// later
theElement.removeEventListener("click", f);
If you're dealing with event listeners, there's a useful pattern for your class methods to be bound:
class MyClass {
init(theElement) {
theElement.addEventListener("click", this.onClick);
theElement.addEventListener("click", this.onClick2);
}
print() {
console.log("print");
}
onClick() {
this.print() // possible error (`this` is not guaranteed to be MyClass)
}
onClick2 = () => {
this.print() // no error, `this` is guaranteed to be of type MyClass
}
}
Keep in mind, however, that this code will create a separate function onClick2 for every object of class MyClass. That can negatively affect your memory usage, if you create lots of MyClass instances and rarely use their onClick listeners.
回答2:
In typescript it is difficult to know what the function call is especially when you "bind" it. Such as:
HTML
<a id="One"></a>
<a id="Two"></a>
and some code creating two objects
let x = new MyClass("I am one", "One");
let y = new MyClass("and I am two", "Two");
with MyClass
class MyClass {
private _myInstance: string;
constructor(ID: string, domID: string) {
this._myInstance = ID;
document.getElementById(domID).addEventListener('click', this.print.bind(this));
}
public print() {
console.log(this._myInstance);
}
}
You will correct get "I am one" when clicking on the "One" a element and "and I am two" when clicking on the second a element.
The situation is more difficult with removing. You need to add a object variable that has the binding included so the my class changes to:
class MyClass {
private _myInstance: string;
private _myDomID: string;
private _myFunc = this.print.bind(this);
constructor(ID: string, domID: string) {
this._myInstance = ID;
this._myDomID = domID;
document.getElementById(domID).addEventListener('click', this._myFunc);
}
public print() {
console.log(this._myInstance);
}
public cleanUp() {
document.getElementById(this._myDomID).removeEventListener('click', this._myFunc);
}
}
回答3:
Already answered question, but IMO the answers here are not well designed regarding to OOP. So, here is my solution:
export class MyClass {
// create member that holds the function reference
protected clickEventListener: EventListener;
// inject the Element
constructor(protected theElement: Element) {
// wrap the class function `onClick` in an arrow function and assign
// to the class member `clickEventListener`
this.clickEventListener = () => this.onClick();
}
onClick() {
console.log("clicked");
}
init() {
// add the event listener to `theElement` and pass only the reference
// of `this.clickEventListener` (no round brackets '()')
this.theElement.addEventListener("click", this.clickEventListener);
}
destroy() {
// to remve the event listener also just pass the `clickEventListener` reference
this.theElement.removeEventListener("click", this.clickEventListener);
}
}
来源:https://stackoverflow.com/questions/38023688/how-do-you-remove-an-event-listener-that-uses-this-in-typescript