12

したがって、カスタム要素を使用する私が作成しているライブラリでは、CustomElementsRegistryインスタンス化する前にクラスを定義する必要があることは明らかです。

現在、これはデコレータで解決されています。

class Component extends HTMLElement {

    static register (componentName) {
        return component => {
            window.customElements.define(componentName, component);
            return component;
        }
    }
}

@Component.register('my-element')
class MyElement extends Component { }

document.body.appendChild(new MyElement());

これは機能しますが、クラスのインスタンス化時にカスタム要素を自動的に登録したいと思います(作成者が作成するすべてのコンポーネントにデコレータを追加する必要がないように)。これは、Proxy.


ただし、私の問題は、コンストラクターで Proxy を使用しようとして、ターゲットのインスタンスを返そうとするとIllegal Constructor、要素がレジストリで定義されていないかのように、まだ取得されることです。

これは明らかに、プロキシ内でクラスをインスタンス化する方法に関係していますが、それ以外の方法はわかりません。私のコードは次のとおりです。

最新の Chrome で実行してください:

class Component extends HTMLElement {

    static get componentName () {
        return this.name.replace(/[A-Z]/g, char => `-${ char.toLowerCase() }`).substring(1);
    }
}

const ProxiedComponent = new Proxy(Component, {

    construct (target, args, extender) {
        const { componentName } = extender;
  	
        if (!window.customElements.get(componentName)) {
            window.customElements.define(componentName, extender);
        }
    
        return new target(); // culprit
    }
});

class MyElement extends ProxiedComponent { }

document.body.appendChild(new MyElement());

例外MyElementをスローしないようにクラスをインスタンス化しているという事実のコンテキストを失うことなく、プロキシ内で継承のチェーンを続行するにはどうすればよいですか?Illegal Constructor

4

2 に答える 2

11

2 つの問題がありました。

  • new target()LibElementカスタム要素として登録されていないインスタンスを作成しました。そして、ここでIllegal Constructorエラーが発生しました。
  • LibElement結果のDOM要素を登録しても<lib-element>、呼び出しが発生new targetし、この時点でjavascriptは子クラスについて認識していません。

私が見つけた唯一の方法は、ReflectAPI を使用してオブジェクトの正しいインスタンスを作成することです。

class LibElement extends HTMLElement {
    static get componentName () {
        return this.name.replace(/[A-Z]/g, char => `-${ char.toLowerCase() }`).substring(1);
    }
}

const LibElementProxy = new Proxy(LibElement, {
    construct (base, args, extended) {
        if (!customElements.get(extended.componentName)) {
            customElements.define(extended.componentName, extended);
        }
    
        return Reflect.construct(base, args, extended);
    }
});

class MyCustomComponent extends LibElementProxy {}
class MyCustomComponentExtended extends MyCustomComponent {}

document.body.appendChild(new MyCustomComponent());
document.body.appendChild(new MyCustomComponentExtended());

そして、カスタム要素の自動登録のためのプロキシ化されたコンストラクターのこのアイデアが本当に気に入りました)

于 2017-12-12T21:36:01.250 に答える