使用lit-html渲染嵌套自定义HTMLElement时子模板覆盖父模板问题
问题原因分析
- lit-html
renderAPI 用法错误:render(template, container)函数的作用是直接将模板渲染到第二个参数指定的容器节点中,本身不会返回可用于innerHTML赋值的HTML字符串。你两次调用render都传入了document.body作为容器,后执行的SubElement渲染会直接覆盖掉之前AppRoot渲染到body的内容,这是内容被替换的核心原因。 - 自定义元素用法不符合规范:浏览器实例化自定义元素时不会调用带自定义参数的构造函数,你直接
new SubElement("I am not root!")塞进lit模板的写法不符合规范,正确用法是在模板中直接编写自定义元素标签<sub-element>,通过属性/插槽传递参数。 - 模板中标签转义错误:
AppRoot的template方法中写的<div>是转义后的字符,会被当成纯文本渲染,而非实际的DOM节点。
修复后可运行代码
HTML代码
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <script src="./index.js" type="module"></script> <app-root></app-root> </body> </html>
JS代码
import { render, html } from './node_modules/lit-html/lit-html.js'; class SubElement extends HTMLElement { static get observedAttributes() { return ['message']; } constructor() { super(); this.message = ''; } attributeChangedCallback(name, oldValue, newValue) { if(name === 'message') { this.message = newValue; render(this.template(), this); } } connectedCallback() { render(this.template(), this); } template() { return html`${this.message}`; } } customElements.define('sub-element', SubElement); class AppRoot extends HTMLElement { constructor() { super(); this.message = "I am root!"; } connectedCallback() { render(this.template(), this); } template() { return html` <div> <p>${this.message}</p> <p><sub-element message="I am not root!"></sub-element></p> </div> `; } } customElements.define('app-root', AppRoot);
修复说明
- 所有
render调用的第二个参数改为自定义元素自身this,仅在当前元素内部渲染内容,不会覆盖全局body的内容 - 移除错误的
innerHTML = render()写法,render本身会完成DOM插入操作 - 自定义元素遵循规范实现,通过
message属性传递参数,监听属性变化自动更新 - 模板中直接编写原生DOM标签和自定义元素标签,无需转义
内容的提问来源于stack exchange,提问作者GeckStar
相关产品推荐
相关产品推荐

