克隆后 <script> 默认不执行,因 <template> 中脚本处于惰性休眠状态,需开发者显式重建并插入新 <script> 节点才能执行;推荐将逻辑抽离至外部 JS 或用 data-* 属性统一初始化。

克隆后 <script> 为什么默认不执行
浏览器把 <template> 当作纯离线暂存区,里面所有 <script> 节点在克隆后仍处于“休眠”状态——既不会自动执行,也不会触发 DOMContentLoaded 或 load 事件。这不是 bug,是规范设计:惰性加载必须由开发者显式激活。
手动执行内联 <script> 的安全做法
别用 eval(),它会丢失作用域、引入 XSS 风险,且无法访问当前模块变量。正确路径是重建 <script> 节点并插入到目标容器(通常是 document.head 或克隆后的 fragment 父容器):
- 遍历克隆后的
script节点:clone.querySelectorAll('script') - 对每个节点,创建新
<script>:const s = document.createElement('script') - 复制关键属性:
s.type = script.type、s.async = script.async、s.defer = script.defer - 设内容:
s.textContent = script.textContent(不要用innerHTML) - 插入:
document.head.appendChild(s)或parent.appendChild(s)
注意:动态插入的 <script> 会按顺序执行,但无法继承父作用域闭包,适合纯函数逻辑或全局初始化代码。
更推荐的替代方案:模板里根本别放 <script>
内联脚本在克隆场景下天然难维护,容易漏处理、重复执行或作用域错乱。实际项目中应:
立即学习“前端免费学习笔记(深入)”;
- 把逻辑抽离到主 JS 文件中,用函数封装(如
initButton(el)),克隆后调用 - 用
data-*属性标记行为意图(如data-init="tooltip"),统一由主逻辑扫描执行 - 若必须依赖模板内脚本,改用
src外链形式,克隆后只设src属性即可触发加载
这样既能避免手动激活的遗漏,也规避了作用域和执行时机问题。
容易踩的坑:克隆后直接 appendChild(script) 不生效
常见错误是拿到克隆后的 script 节点,直接 parent.appendChild(script)——这不会执行,因为浏览器只对新插入 DOM 的 <script> 标签做执行判定,且仅限首次挂载。而克隆出来的 script 已是“已解析节点”,再 append 只是移动,不触发重执行。
真正起效的是新建 <script> 并设 textContent 或 src,让浏览器把它当作全新脚本处理。
最易被忽略的是:如果脚本依赖 DOM 就绪(比如操作 document.querySelector),必须确保插入时机在克隆内容已挂入文档流之后,否则查不到元素。



















