【发布时间】:2021-12-19 19:01:03
【问题描述】:
尝试将使用原型编写的 js“类”转换为 ES6 类,新版本可以正常运行,但不会在 DOM 中显示任何内容,而旧版本可以。
类如何工作的细节应该不重要,但是,我正在尝试在 preact 中实现一个自定义 Web 组件。
// common imports for completeness
import { h, render, FunctionComponent, VNode } from "preact";
// old version: working ✅
function connectedCallback() {
this._vdom = toVdom(this, this._vdomComponent);
render(this._vdom, this._root);
}
function disconnectedCallback() {
render((this._vdom = null), this._root);
}
function toVdom(element: HTMLElement, nodeName?: FunctionComponent<any>) {
if (element.nodeType === 3) return element.data;
if (element.nodeType !== 1) return null;
const children = Array.from(element.childNodes).reverse().map(cn => toVdom(cn));
return h(nodeName || element.nodeName.toLowerCase(), {}, children);
}
function createCustomElement(Component: FunctionComponent<any>) {
function PreactElement() {
const inst = Reflect.construct(HTMLElement, [], PreactElement);
inst._vdomComponent = Component;
inst._root = document.body;
return inst;
}
PreactElement.prototype = Object.create(HTMLElement.prototype);
PreactElement.prototype.constructor = PreactElement;
PreactElement.prototype.connectedCallback = connectedCallback;
PreactElement.prototype.detachedCallback = disconnectedCallback;
return PreactElement;
}
// new version: not working ❌
const createCustomElement = (Component: FunctionComponent<any>) => {
return class PreactElement extends HTMLElement {
private readonly _vdomComponent = Component;
private readonly _root = document.body;
private _vdom: VNode<any> | null = null;
private static toVdom = (element: HTMLElement, nodeName?: FunctionComponent<any>) => {
if (element.nodeType === 3) return element.data;
if (element.nodeType !== 1) return null;
const children = Array.from(element.childNodes).reverse().map(cn => PreactElement.toVdom(cn));
return h(nodeName || element.nodeName.toLowerCase(), {}, children);
}
connectedCallback = () => {
this._vdom = PreactElement.toVdom(this, this._vdomComponent);
render(this._vdom, this._root);
}
disconnectedCallback = () => {
render((this._vdom = null), this._root);
}
};
};
【问题讨论】:
-
调试时间!向方法添加断点(如果您的环境不支持,则调用
console.log())。你期望被调用的所有方法实际上都被调用了吗?是否所有变量都具有预期值。给老版本的代码加上同样的调试,有什么不同? -
"新版本运行时出现错误..." 请出示。
-
如果有,打字稿应该捕捉它。但是你可以通过在每个方法中添加
console.log('myMethodName:this', this)来验证它,看看它看起来是否正确。 -
不知道这是否是您的问题的根源,但在工作/原型版本中有一个“detachedCallback”方法,而您的类版本有“disconnectedCallback”。
-
感谢@AlexWayne,我找到了问题的根源。事实证明,类上的箭头函数没有实现基类的方法。我不得不将 connectedCallback 和 disconnectedCallback 更改为常规类函数。
标签: javascript reactjs typescript web-component preact