标签不是开箱即用的组件机制,它只是浏览器跳过解析的离线容器,必须通过document.importnode(tmpl.content, true)克隆并手动填充数据后插入dom才能生效。

<template></template> 标签不是“开箱即用”的组件机制,它只是浏览器跳过解析的离线容器。想靠它支撑轻量级前端框架,必须手动克隆、填充、挂载——否则它什么都不会做。
为什么 <template></template> 的 content 属性是唯一入口
很多人一上来就写 document.querySelector('template').innerHTML,结果拿到空字符串。这是因为 <template></template> 的子节点被包裹在 DocumentFragment 里,根本不在 HTML 字符串中。你只能通过 tmpl.content 访问真实结构。
-
tmpl.innerHTML永远为空,别用 -
tmpl.textContent返回纯文本(含换行缩进),但无法操作 DOM 节点 -
tmpl.content.cloneNode(true)是浅克隆,会丢掉表单状态(如<input checked>的选中态) - 必须用
document.importNode(tmpl.content, true)才能保留原生交互行为
填值时为什么不能直接用 innerHTML
模板里写 <div class="title">{{title}}</div>,然后用正则替换或 innerHTML = data.title,看似快,实则埋雷。
- 用户输入若含
<script>alert(1)</script>,innerHTML直接执行 XSS - 已有事件监听器(比如按钮上绑的
onclick)会被销毁 - 表单控件状态(
value、checked、selected)不会同步更新 - 正确做法:文本内容用
textContent,表单字段用value或checked属性赋值
批量渲染时为何必须用 DocumentFragment
循环 100 次调用 container.appendChild(cloned),等于让浏览器反复重排重绘,卡顿明显;500 条基本不可用。
- 每次
appendChild都触发 layout + paint,性能损耗线性增长 - 应先创建
const frag = document.createDocumentFragment() - 循环中只往
frag里 append,最后一次性container.appendChild(frag) -
frag不在真实 DOM 树中,无渲染开销
<slot></slot> 和内联事件在普通 DOM 中完全无效
有人把 Web Components 的写法直接挪到 <template></template> 里:<slot name="header"></slot>,再试图用 JS 填充,结果毫无反应。
-
<slot></slot>只在 Shadow DOM 中激活,light DOM 下不解析、不报错、也不生效 -
onclick="doSomething()"这类内联 handler,在cloneNode或importNode后不会自动绑定 - 想支持事件,得手动调用
cloned.querySelector('button').addEventListener('click', ...) - 硬编码
id="modal"会导致多次使用时 ID 冲突,应改用data-id或动态生成标识
真正难的不是克隆模板,而是让每次填充都保持表单状态、不破坏事件、不引入 XSS、不拖垮性能——这些细节没处理好,<template></template> 就只是个好看的占位符。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











