中的脚本不执行,因其内容被设计为离线documentfragment,解析时跳过脚本执行与资源加载;正确做法是克隆后手动创建元素并注入,禁用eval以防xss。

为什么里的脚本不执行
<template></template>是浏览器的“内容暂存区”,所有子节点(包括<script></script>)在解析阶段就被跳过,既不执行、也不触发资源加载。这不是 bug,而是设计——它保证模板内容可安全复用,避免重复执行或副作用。
常见错误现象:template.innerHTML取字符串再赋给el.innerHTML,结果<script>console.log(1)</script>完全静默;或克隆后直接插入,但alert()没弹出。
- 正确做法:遍历克隆后的
fragment.querySelectorAll('script'),对每个节点创建新<script></script>元素,复制type、async等属性,再设textContent并appendChild到目标容器 - 禁止用
eval(script.textContent)——无法访问当前作用域变量,且XSS风险极高(尤其模板来自服务端) - 注意:动态创建的
<script></script>会按顺序执行,但不会继承父级闭包,适合纯函数逻辑
如何让里的图片/iframe真正懒加载
<template></template>本身不触发任何加载,但一旦你调用cloneNode(true)并把节点插入文档流,<img src="...">和<iframe src="..."></iframe>就会立刻发起请求——除非你提前干预。
- 方案一:插入前加
loading="lazy"——仅限现代浏览器,且必须确保父容器无transform、overflow: hidden等干扰属性 - 方案二:用
data-src代替src,插入后再批量替换:img.src = img.dataset.src,兼容性更好,也便于统一控制加载时机 - 方案三:对
<iframe></iframe>,初始用srcdoc="<h1>Loading...</h1>"占位,等需要时再赋值src,彻底规避预加载
克隆后Web Components不升级怎么办
如果模板里含自定义元素(如<my-card></my-card>),其connectedCallback只在首次插入 DOM 时触发。若你先克隆、再修改内容、最后插入,组件可能卡在“未升级”状态——DOM 已挂载,但customElements.define()还没跑完。
- 确保所有自定义元素定义(
customElements.define('my-card', ...))在克隆前已完成,否则浏览器不认识该标签 - 克隆后、插入前不要调用
document.body.appendChild(fragment)这类直接挂载;应先container.appendChild(fragment),再让框架或注册逻辑接管 - 若使用 Shadow DOM,优先用
document.importNode(tmpl.content, true)而非cloneNode(true),前者能更好保留绑定上下文
为什么不能直接当Vue/React组件用
Vue 的<template></template>是编译时语法糖,React 的 JSX 是 JS 表达式,而 HTML 原生<template></template>只是静态 DOM 片段容器——它没有响应式、无生命周期、不解析插值(如{{title}}),也不支持 props 或事件绑定。
- 所谓“传参”,本质是 JS 工厂函数接收对象,再手动映射到克隆后的节点:
node.textContent = data.title或node.dataset.value = data.id - 禁止在模板内写硬编码 ID(如
id="card-1"),多次复用会导致 ID 冲突,影响 CSS 选择器或document.getElementById - 若需高频更新,缓存首次生成的
DocumentFragment,后续只改textContent或dataset,避免重复克隆和重排
最易被忽略的是:克隆后节点若含表单控件(<input checked>、<select></select>),用cloneNode(true)会丢失选中态,必须用document.importNode()才能保真。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











