typescript - bir dekoratörün içinden this.shadowRoot


Özel HTML öğelerimdeki çoğu olay işleyicisi şöyle görünüyor,

  totalChanged() {
    if (!this.shadowRoot) return
    const t = this.shadowRoot.querySelector('#total')
    if (t) t.innerHTML = String(this.price * this.quantity)
  }

Onu bir şeye benzer şekilde yapmak mümkün mü?

  @event('#total')
  totalChanged() {
    return String(this.price * this.quantity)
  }

Bir dekoratörde shadowRoot'a nasıl ulaşacağımı bilmiyorum, this dekoratör modülüne kendisine referans veriyor, HTMLElement'e değil. Ve proto, özel elementimin prototipi, aynı zamanda istediğim this de değil.

export function event(select: string) {
  return (proto: any, propName: string) : any => {
    console.log(this.shadowRoot)
  }
}

Burada this sadece tanımsız

export function event(select: string) {
  return function (proto: any, propName: string) : any {
    console.log(this.shadowRoot)
  }
}

DÜZENLE: Örnek

index.html

<test-2></test-2>
<script src="test2.js"></script>

test2.ts => test2.js (hedef ES2017)

function defineClass(tagname: string) {
  return function classDecorator<T extends {new(...args:any[]):{}}>(constructor:T) {
    console.log("Define: " + constructor.name)
    window.customElements.define(tagname, constructor)
    return class extends constructor {
      newProperty = "decorator";
      hello = "decorator";
    }
  }
}

function myevent(select: string) {
  return function (this:any, proto: any, propName: string, descriptor: PropertyDescriptor) : any {
    let originalMethod = descriptor.value;
    descriptor.value = function(this:any, ...args: any[]) {
      console.log('test', this)
      return originalMethod.apply(this, args) 
    }
    return descriptor;
  }
}

@defineClass('test-2')
class Greeter2 extends HTMLElement{
  property = 'property2'
  hello = 'hello2'
  constructor() {
    super()
    console.log(this.hello)
  }
  @myevent('hello')
  helloFn() {}
  connectedCallback() { }
  disconnectedCallback() { }
  attributeChangedCallback(name: string, oldValue: string, newValue: string) { }
  adoptedCallback() { }
}
console.log('test-2: ', document.querySelector('test-2').hello)

@defineClass('test-3')
class Greeter3 {
  property = 'property3'
  hello = 'hello3'
  constructor() {
    console.log(this.hello)
  }
  @myevent('hello')
  helloFn(){}
}
console.log('test-3: ', new Greeter3());

EDIT2: new Greeter3().helloFn() metodunu çağırmam gerekiyordu, Diullei'nin cevabına bakın

Cevap #1

Nesne bağlamına erişmek için descriptor argümanı eksik. Bu kodu deneyin:

export function event(select: string) {
    return function (proto: any, propName: string, descriptor: PropertyDescriptor) : any {
        let originalMethod = descriptor.value; // saving the original function

        descriptor.value = function(...args: any[]) { // changing the original function body
            console.log(this.shadowRoot);
            return originalMethod.apply(this, args); // calling original function
        }
        return descriptor;
    }
}