内容变更后重新渲染hyperHTML至同一元素及子元素渲染问题
问题1:MutationObserver 监听内容变更后,hyperHTML 渲染不更新元素内容
场景还原
我在用 hyperHTML 开发自定义元素库时,需要通过 MutationObserver 监听元素内容变更来触发重新渲染。但遇到了奇怪的情况:明明看到 hyperHTML 提示已渲染到目标元素,可元素的 innerHTML 就是没更新,甚至能看到 hyperHTML 的注释标记被移除,但直接重新调用 render 和 hyperHTML.bind 一开始都没效果。
修复方案
后来发现重新调用 hyperHTML.bind(elem) 之后再执行正常的渲染逻辑,就能解决这个问题。
原因分析
hyperHTML 的 bind 方法会建立元素与渲染逻辑的关联关系,当元素内容被外部操作(比如 jQuery 修改、原生 DOM 直接操作)改变后,hyperHTML 内部维护的绑定状态可能会失效。重新调用 bind 相当于重置了这个关联,让后续的 render 操作能正确将内容同步到目标元素上。
问题2:渲染自定义元素时,子内容被错误渲染到元素外部
场景还原
在实现类似局部模板的自定义元素(比如 <user-list>)时,第三方内容的渲染已经正常,但渲染另一个自定义元素 <crazy-cats> 时出了问题。用 Html xxx: ${this.wrapedContent} zzzz 语法渲染后,wrapedContent的内容跑到了
当前输出:
wrapedContent: ppp time:11:35:48 ~ crazy-cats: **Party 11:35:48** xxx: zzzz <crazy-cats>Party 11:37:21 xxx: <!--_hyper: -362006176;--> zzzz </crazy-cats>
期望输出:
wrapedContent: ppp time:11:35:48 ~ crazy-cats: xxx: **Party 11:35:48** zzzz <crazy-cats> xxx: Party 11:37:21 zzzz </crazy-cats>
问题分析
这是因为 hyperHTML 在解析模板时,如果直接把自定义元素的内容作为变量插入到外部模板中,会把变量对应的节点解析到自定义元素的外部,而不是作为子节点插入到元素内部。本质是模板语法的使用方式不符合 hyperHTML 处理自定义元素的逻辑。
解决方案
你可以调整内容传递和渲染的方式:
方案一:让自定义元素内部负责渲染内容
给自定义元素添加一个接收内容的属性,然后在元素的render方法中渲染这个内容:class CrazyCats extends HyperElement { render() { // 内部渲染传入的内容 return this.html`<div>xxx: ${this.props.content} zzzz</div>`; } } // 父组件中传递内容 Html`<crazy-cats content=${this.wrapedContent}></crazy-cats>`方案二:直接在自定义元素标签内部写模板内容
把要渲染的内容直接放在自定义元素的标签内部,hyperHTML 会正确识别为元素的子节点:Html`<crazy-cats>xxx: ${this.wrapedContent} zzzz</crazy-cats>`
这样就能确保内容被渲染到自定义元素的内部,而不会跑到外部。
内容的提问来源于stack exchange,提问作者aSmater.Me

