ค้นหาเว็บไซต์

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);
  }
}

บทความที่เกี่ยวข้อง