原型实现的Preact自定义组件转ES6 Class后DOM无内容如何解决
问题根因
- 你使用箭头函数定义
connectedCallback、disconnectedCallback两个Web Components生命周期回调:箭头函数赋值的类成员属于实例自身属性,而浏览器只会在自定义元素类的原型链上查找标准生命周期方法并触发,因此这两个回调实际根本没有执行,自然没有渲染内容。 - 旧版本的原型写法是直接把回调挂载到类原型上,符合浏览器的查找规则,因此可以正常触发。
- 额外说明:旧版本里写的
detachedCallback是早已废弃的非标准API,你之前能正常运行应该是刚好没用到元素断开的逻辑,标准API是disconnectedCallback,新版本你已经改对了这个命名。
修复后的可运行代码
// 通用导入 import { h, render, FunctionComponent, VNode } from "preact"; const createCustomElement = (Component: FunctionComponent<any>) => { return class PreactElement extends HTMLElement { private _vdomComponent = Component; // 如果你需要DOM隔离,建议把_root改为this.attachShadow({ mode: 'open' }) private _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 as HTMLElement)); 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); } }; };
使用示例
注册自定义元素时需要确保标签名符合规范(必须包含短横线):
const MyCustomElement = createCustomElement(你要封装的Preact组件); customElements.define('my-custom-element', MyCustomElement);
内容的提问来源于stack exchange,提问作者thecartesianman
相关产品推荐
相关产品推荐

