javascript - การผูก Decorator addEventListener ไม่ทำงาน
ฉันกำลังพยายามสร้างเดคอเรเตอร์ที่จะรับเมธอดในคลาสและเพิ่มมันเข้าไปยังอีเวนต์ลิสต์เนอร์บนหน้าต่าง อย่างไรก็ตามเมื่อฉันทำเช่นนั้น มันไม่ได้เชื่อมโยงกับคลาส และฉันไม่แน่ใจว่าทำไม...
export function Listener(listenerLocation: string) {
return (target: any, key: string, descriptor: PropertyDescriptor) => {
const [nodeOrEvent, event] = listenerLocation.split(':')
console.log(target)
if (nodeOrEvent === 'window' && event.length > 0) {
window.addEventListener(event, target[key].bind(target.constructor))
}
}
}
บันทึกในตัวตกแต่งพิมพ์ดังต่อไปนี้:
export class Canvas {
constructor(
public readonly width: number,
public readonly height: number,
public readonly canvas: HTMLCanvasElement | string
) {
console.log(this.width)
// Set width/height on canvas
}
@Listener('window:resize')
windowResize() {
console.log('w', this.width)
}
}
เมื่อคลาสถูกโหลด console.log ในคอนสตรัคเตอร์จะแสดงขนาดที่ถูกต้องของ -1 (บอกคลาสให้ปรับขนาดแคนวาสเป็นความกว้างสูงสุด) แต่เมื่อฉันปรับขนาดหน้าต่าง ตัวฟังเหตุการณ์จะทำงาน แต่ this.width เป็น undefined
แก้ไข
ฉันได้ทำการเปลี่ยนแปลงตัวตกแต่งเล็กน้อย ฉันไม่แน่ใจว่ามันผูกหรือไม่ แต่ผลลัพธ์ยังคงเป็น undefined
export function Listener(listenerLocation: string) {
return (target: any, key: string, descriptor: PropertyDescriptor) => {
const [nodeOrEvent, event] = listenerLocation.split(':')
Object.defineProperty(target, key, {
configurable: true,
get() {
console.log('here', this)
const bound = descriptor.value.bind(this)
Object.defineProperty(this, key, {
value: bound,
configurable: true,
writable: true
})
return bound
}
})
if (nodeOrEvent === 'window' && event.length > 0) {
window.addEventListener(event, target[key])
}
}
}
คำตอบ #1
เนื่องจากวิธีการ windowResize Decorator ถูกเรียกก่อนที่จะสร้างอินสแตนซ์ ความกว้างจึงไม่ได้ถูกผูกกับฟังก์ชัน windowResize เนื่องจากเราต้องผูกหลังจากสร้างอินสแตนซ์เท่านั้น เราจึงสามารถพิจารณาการเพิ่มคลาส Decorator และขยายฟังก์ชันการสร้าง https://codesandbox.io/s/hungry-chihiro-mungp?file=/src/app/app.component.ts:0-627
import {
Component
} from "@angular/core";
type Consturctor = {
new(...args: any[]): any
};
function ResizeListener < T extends Consturctor > (BaseClass: T) {
return class extends BaseClass {
constructor(...args) {
super(...args);
window.addEventListener("resize", this.windowResize.bind(this));
}
};
}
@Component({
selector: "app-root",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.css"]
})
@ResizeListener
export class AppComponent {
title = "CodeSandbox";
constructor() {
console.log("w", "IN parent");
}
windowResize() {
console.log("w", this.title);
}
}