【发布时间】:2018-05-26 13:26:34
【问题描述】:
因此,在我创建的使用自定义元素的库中,您显然需要在实例化之前在 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 来完成。
不过,我的问题是,当我尝试在构造函数上使用代理并尝试返回目标的实例时,我仍然得到 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异常?
【问题讨论】:
-
我相信这是预期的行为。你应该可以做到
document.createElement(LibElement.componentName)。通过扩展原生HTMLElement创建的类实际上对于构造元素无效,而应该使用document.createElement来构造。 -
作为解决方案,您可以在代理构造中执行
return document.createElement(target.componentName)。 -
@shamsup 你是说它们对于根据规范构造元素无效,还是说它根本不起作用——因为它确实起作用(在 chrome 中)。
-
我的意思是即使只是
class Custom extends HTMLElement {}; new Custom();也会抛出非法构造函数错误,因为HTMLElement不能用new关键字创建,必须通过document.createElement创建 -
这仅适用于尚未将类添加到
CustomElementsRegistry
标签: javascript custom-element proxy-pattern