HTML template标签本身不响应数据变化,它只是离线DOM片段容器,需通过template.content.cloneNode(true)克隆后手动填值,禁用innerHTML防XSS,批量插入须用DocumentFragment提升性能。

HTML <template></template> 标签本身不响应数据变化
浏览器原生的 <template></template> 只是离线 DOM 片段容器,它不会监听 JS 变量、不触发重渲染、也不自动填充占位符。你写 <template><div>{{name}}</div></template>,document.querySelector('template').content.innerHTML 依然返回空字符串——因为 content 是只读 DocumentFragment,且 {{}} 不是 HTML 语法,浏览器直接忽略。
- 常见错误现象:
template.innerHTML始终为空;循环中反复appendChild却只显示最后一项(因共用同一节点引用) - 必须用
template.content.cloneNode(true)获取可复用副本,每次克隆后手动填值:cloned.querySelector('.name').textContent = data.name - 填值时避免用
innerHTML拼接用户输入,否则引入 XSS 风险;纯文本场景优先用textContent -
<template></template>里的<script></script>和<style></style>在克隆后不会执行或生效,别指望它自动加载逻辑或样式
React/Vue 的“组件”不是 HTML 标签,而是 JS 运行时产物
写 <mybutton>Click</mybutton> 看似像 HTML,实际被编译成 React.createElement('MyButton', {}, 'Click') 或 Vue 的渲染函数调用。首字母大写的标签名会被框架识别为自定义组件,小写的(如 <div>)才转为原生 DOM 元素。
<ul>
<li>纯 HTML 文件里打开 <code>{{ msg }} 或 v-for="item in list",浏览器只会原样显示,不报错也不生效
if 或 for 语句,得用三元表达式、&& 逻辑运算符或 Array.map()
<template></template> 下只能有一个根,需用 <fragment></fragment> 或 <div> 包裹
<li>脱离框架运行时,那些标签就是静态字符串——框架的响应式系统、虚拟 DOM 差异比对、更新队列调度,全靠 JS 在内存中维护,HTML 本身零执行能力</li>
<h3>服务端渲染(SSR)不是拼字符串,而是 hydration 边界对齐</h3>
<p>用 <code>res.send('<div id="root"></div>') 直接吐 HTML,客户端 React/Vue mount 时大概率静默失败:光标丢失、事件没绑定、状态错乱。原因在于 hydration 要求服务端生成的 DOM 结构、属性顺序、文本内容与客户端首次 render 完全一致。- 服务端必须注入初始状态,如
window.__INITIAL_STATE__ = {...},且不能有额外或标签 - 模板引擎(如 EJS/Handlebars)要启用缓存:启动时预编译模板函数,避免高并发下重复解析打满 CPU
- 压缩 HTML 时必须配置
ignoreCustomFragments,否则{{user.name}}被删掉,导致白屏或ReferenceError - 用
<template></template>动态插入服务端返回的 HTML 片段时,该区域无法被 hydration 接管——它只是静态 DOM,事件和状态都不会恢复
局部更新不能靠 innerHTML,得用 replaceChildren() 或事件委托
container.innerHTML = newHtml 看似简单,但会销毁整个子树,所有已绑定的事件监听器全部失效。这不是 bug,是规范行为。
立即学习“前端免费学习笔记(深入)”;
- 常见失灵场景:表格每行删除按钮点击后无效;表单提交后校验提示消失
- 安全替代方案:
container.replaceChildren(...nodes)(现代浏览器支持),或用事件委托把监听器挂到父容器上:container.addEventListener('click', e => { if (e.target.matches('.delete-btn')) handleDelete(e) }) - 服务端返回的是 HTML 字符串(如
'<tr><td>xxx</td></tr>'),不能直接塞进<tbody>——浏览器会自动补全结构导致错乱;正确做法是先过 <code><template></template>解析再克隆插入 - 批量插入大量节点时,用
DocumentFragment缓存所有克隆节点,最后一次性appendChild,避免频繁重排
真正容易被忽略的是:所谓“组件化”和“响应式更新”,全是 JavaScript 在幕后调度的结果。HTML 标签只是它们选择的序列化外观,不是运行基础。你改了 JS 数据,框架决定要不要更新、更新哪块、怎么更新;你改了 HTML 字符串,它就只是字符串。



















