原生 template 标签仅作内容占位,不自动渲染或绑定数据,需手动克隆 content 并配合 Mustache、new Function 等方案实现批量 HTML 生成。

为什么直接用 template 标签写 HTML 模板会失效
浏览器默认忽略 <template></template> 内容,不渲染、不执行脚本、不加载资源——这看似“安全”,但若你期望它像 Vue 或 Handlebars 那样自动插入数据并生成 DOM,就会发现什么都没发生。它只是个容器,不是引擎。
常见错误现象:document.querySelector('template').content.innerHTML 返回空字符串,或取到的是原始未替换的占位符(如 {{name}});innerHTML 赋值后事件绑定丢失;模板重复使用时 content 被移走导致第二次调用为空。
- 必须手动克隆:
template.content.cloneNode(true),否则content是“活”的 DocumentFragment,只能用一次 - 原生
<template></template>不解析表达式,需配合String.prototype.replace或eval(不推荐)做简单替换 - 若模板含
<script></script>或<style></style>,克隆后不会自动执行,需额外遍历处理
用 mustache.render 批量生成 HTML 的最小可行路径
Mustache 是零依赖、无逻辑的模板引擎,适合纯数据填充场景,比如生成静态页面列表、邮件模板、配置文档。它不支持 if/for 语法,但正因如此,批量渲染时更可控、更难出错。
使用场景:从 JSON 数组生成一组卡片 HTML 字符串,再一次性注入 container.innerHTML;或导出为文件供后续服务端渲染。
立即学习“前端免费学习笔记(深入)”;
- 安装:
npm install mustache,或直接引入 CDN:<script src="https://unpkg.com/mustache@4.2.0/mustache.min.js"></script> - 模板字符串里用
{{key}},数据对象字段名必须严格匹配,不存在则留空(不会报错) - 批量渲染示例:
const templates = data.map(item => Mustache.render('<div class="card"><h3>{{title}}</h3><p>{{desc}}</p><div class="aritcle_card flexRow"> <div class="artcardd flexRow"> <a class="aritcle_card_img" href="/xiazai/skill11445" title="使用华数设计生成高保真HTML原型、演示文稿、动画和设计评审"><img src="https://img.php.cn/upload/skill/001/246/273/6adaf20e695c2374.jpg" alt="使用华数设计生成高保真HTML原型、演示文稿、动画和设计评审" ></a> <div class="aritcle_card_info flexColumn"> <a href="/xiazai/skill11445" title="使用华数设计生成高保真HTML原型、演示文稿、动画和设计评审">使用华数设计生成高保真HTML原型、演示文稿、动画和设计评审</a> <p>使用经过文档化的设计技能,从真实的品牌或项目背景中生成HTML原生原型、幻灯片、动态演示、可视化图表和评审流程。</p> </div> <a href="/xiazai/skill11445" title="使用华数设计生成高保真HTML原型、演示文稿、动画和设计评审" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span> </a> </div> </div></div>', item));<br>container.innerHTML = templates.join(''); - 注意:Mustache 对
<code>>自动转义,若需输出原始 HTML,改用{{{html}}}(三花括号)
new Function() 实现极简模板函数,比字符串替换快且可复用
当数据结构固定、性能敏感(比如每秒生成数百个模板),又不想引入第三方库时,new Function() 是轻量选择。它把模板编译成真实函数,变量作用域清晰,执行快,且天然支持 JS 表达式。
容易踩的坑:new Function() 在 CSP 环境下被禁用;参数名与数据字段冲突会导致静默失败;错误堆栈指向“anonymous”函数,调试困难。
- 基础写法:
const tpl = new Function('data', 'with(data){return `<div>${name} - ${age}</div>`;}'); - 更安全的做法是显式解构:
const tpl = new Function('data', 'return `<div>${data.name} - ${data.age}</div>`;'); - 批量生成时,先定义函数一次,再循环调用:
items.map(item => tpl(item)),避免反复编译 - 不要拼接用户输入进模板字符串,否则构成代码注入——仅限可信数据源
Vue / React 组件中批量生成 HTML 字符串的隐藏风险
在 Vue 中用 v-for 渲染后,通过 el.outerHTML 取 HTML 字符串,看似方便,实则危险:它包含响应式绑定标记(如 data-v-xxx)、未求值的指令(v-if 还在标签上)、甚至内联样式绑定残留。React 的 ReactDOMServer.renderToString 更可靠,但只在 Node 环境可用。
真正需要“生成 HTML 字符串”的典型场景,往往发生在导出、打印、邮件发送等脱离运行时上下文的环节——这时模板引擎或纯函数才是正路,而不是从已挂载组件里“抠”HTML。
- Vue 浏览器端慎用
el.outerHTML:它可能含未激活的v-show元素、ref占位节点、服务端预渲染留下的注释节点 - React 若必须在浏览器生成 HTML,请用
createRoot+render到临时div,再取innerHTML,但要确保组件无副作用(如useEffect) - 最稳方案:把模板逻辑抽离为纯函数,和框架解耦,既可用于 SSR,也可用于客户端批量生成
批量生成 HTML 的核心,从来不是“怎么写模板”,而是“谁负责数据绑定、谁控制执行时机、谁承担 XSS 风险”。选错一层,后面全是补丁。


















