自定义Web组件实例引用不一致问题排查与解决问询
问题:自定义Web组件实例操作不一致导致DOM无更新
相关代码
AppUiComponent 代码
import ComponentFactoryInstance from "../../ui/componentFactory"; import notifier from "../../utils/notifier"; export default class AppUiComponent { constructor() { } static build() { const appRoot = document.createElement('div'); const toolBar = ComponentFactoryInstance.create('girovo-tool-bar'); const toolBarEditingPan = document.createElement("div"); toolBarEditingPan.setAttribute("style", "display:flex;"); const _toolBar = toolBarEditingPan.appendChild(toolBar); notifier.subscribe("build_tool_ui", data => { (_toolBar as iToolBar).buildTool({icon: data!.icon}); // or // (toolBar as iToolBar).buildTool({icon: data!.icon}); }); appRoot.appendChild(toolBarEditingPan); return appRoot; } }
ToolBar 自定义组件代码
import ComponentFactoryInstance from "./componentFactory"; import idGenerator from "../utils/idGenerator"; export default class ToolBar extends HTMLElement { shadow: ShadowRoot; _id: string | void; parent: any; constructor() { super(); this._id = idGenerator().next().value; this.shadow = this.attachShadow({ mode: "open" }); } connectedCallback() { } buildTool(toolData: Record<string, any>){ const tool = ComponentFactoryInstance.create("girovo-toolicon", { width: "25px", height: "25px", src: toolData.icon }); this.shadow.appendChild(tool); } }
问题描述
上述代码中,AppUiComponent通过ComponentFactory生成girovo-tool-bar自定义Web组件实例,添加到DOM后调用其buildTool方法添加子组件,但DOM无变化。控制台日志显示操作的实例_id与DOM中渲染的实例_id不一致,说明操作的并非同一个组件实例。
解决方案
1. 排查ComponentFactory.create方法逻辑
核心问题大概率出在ComponentFactoryInstance.create方法上,需要确保该方法每次调用create('girovo-tool-bar')时:
- 仅生成一个ToolBar实例,无重复创建或克隆实例的逻辑;
- 直接返回新创建的实例本身,没有返回额外生成的节点。
比如要避免这类错误逻辑:
// 错误示例:重复创建实例 create(tagName) { const elem = document.createElement(tagName); // 错误:额外实例化组件类,导致返回的实例和DOM中挂载的不是同一个 return new ToolBar(); }
正确的逻辑应该是直接返回document.createElement(tagName)生成的实例(自定义组件注册后,该方法会返回对应类的实例),或者正确实例化组件类并返回。
2. 验证实例引用一致性
在代码中添加日志,确认实例是否为同一个:
- 在AppUiComponent的build方法中打印
toolBar._id; - 在ToolBar的
connectedCallback中打印this._id;
如果两者不一致,说明ComponentFactory的create方法返回的实例和最终挂载到DOM的实例不是同一个,需修正create方法逻辑。
3. 简化实例引用
代码中const _toolBar = toolBarEditingPan.appendChild(toolBar)属于冗余赋值,appendChild返回的就是传入的toolBar实例,直接使用toolBar变量即可,减少引用混淆:
notifier.subscribe("build_tool_ui", data => { (toolBar as iToolBar).buildTool({icon: data!.icon}); });
4. 确认组件注册正确性
确保girovo-tool-bar组件仅正确注册一次:
// 正确的注册方式(通常在ComponentFactory或ToolBar文件中) if (!customElements.get('girovo-tool-bar')) { customElements.define('girovo-tool-bar', ToolBar); }
重复注册会被浏览器忽略,可能引发实例异常。
内容的提问来源于stack exchange,提问作者Andrew Naem
相关产品推荐
相关产品推荐

