轻量级渲染器应优先用domparser将字符串安全转为dom节点,避免innerhtml导致的xss、事件丢失与回流问题;静态内容可用字符串渲染,动态交互宜用事件委托或虚拟dom;模板替换须严格转义以防结构污染。

先转字符串,再安全注入 DOM
浏览器原生支持 innerHTML,但直接赋值有风险。更稳妥的做法是用 DOMParser 解析字符串为真实节点:
- 避免 XSS:不拼接用户输入,或提前对内容做 HTML 转义(如
→ <code><) - 保留结构语义:
DOMParser会按标准解析嵌套、自闭合标签,比正则或手动拼接可靠得多 - 示例写法:
<script></script>
function stringToDOM(str) {
const parser = new DOMParser();
const doc = parser.parseFromString(`${str}`, 'text/html');
return Array.from(doc.body.childNodes);
}
避免 innerHTML 导致的事件与状态丢失
用 innerHTML 替换整个容器内容时,原有绑定的事件监听器、表单值、焦点状态都会清空。这不是 bug,是设计使然。
- 静态内容用字符串渲染没问题;动态交互区域建议用虚拟 DOM 或局部更新
- 若必须用字符串更新,可结合事件委托:把事件监听绑定在父容器上,用
e.target匹配实际触发元素 - 表单控件(如
<input>)值不会自动同步到字符串模板里,需手动读取/写入
用文档碎片减少回流次数
一次插入多个节点时,逐个 appendChild 会多次触发回流。改用 DocumentFragment 批量操作:
- 创建碎片:
const frag = document.createDocumentFragment() - 把所有新节点
appendChild到 frag 中 - 最后只执行一次
container.appendChild(frag),浏览器仅回流一次 - 比拼接字符串再设
innerHTML更可控,也比逐个挂载快得多
模板字符串 + 数据替换要谨慎设计
简单场景可用 str.replace(/{{key}}/g, data[key]),但注意边界:
- 别让数据污染 HTML 结构:例如
data.title = '<script>alert(1)</script>'会破坏 DOM 树 - 属性值要用引号包裹并转义:
value="{{val}}" → value=""${escape(val)}"" - 复杂逻辑(循环、条件)建议交给编译型模板(如 art-template),而非运行时正则替换











