为什么不't克隆节点<脚本>执行标记

Why don't cloneNode <script> tags execute?

本文关键字:gt 脚本 执行 lt 为什么不 节点      更新时间:2024-06-19

克隆<script>标记不执行。为什么?

示例:

<script id="hello">
  console.log("hello execution count ", window.helloCount++);
</script>
<script id="action">
  document.body.appendChild(
    document.getElementById('hello').cloneNode(true));
  console.log('cloned the script');
</script>

执行后,文档中有两个hello脚本,但只有一个执行了。

http://jsbin.com/zuxoro/1/edit?html,控制台,输出

这是我正在处理的一个更大问题的一部分,所以我知道这是一件愚蠢的事情

W3C HTML5规范要求此行为。

每个<script>元素都有一个名为"已启动"的属性标志。说明书上写着:

最初,脚本元素必须取消设置此标志(脚本块在创建时不是"已启动")如果在要克隆的元素上设置了"已启动"标志,则脚本元素的克隆步骤必须在副本上设置该标志

然后,后来:

如果脚本元素被标记为"已启动",则用户代理此时必须中止这些步骤。脚本未执行。

解决方案不是克隆脚本元素,而是创建填充了相同内容的全新元素。

我不知道为什么它不能与cloneNode一起使用,但您可以通过将innerHTML复制到新的脚本节点来获得相同的结果。

var clone = document.createElement('script');
clone.innerHTML = document.getElementById('hello').innerHTML;
document.body.appendChild(clone);
console.log('copied the script');
<script>
  window.helloCount = 1;
</script>
<script id="hello">
  console.log("hello execution count ", window.helloCount++);
</script>
<div>Copied scripts do execute</div>

原则上,浏览器在页面上执行<script>时会执行以下操作:

如果脚本<script>在执行以下操作之前未执行:

  1. <script>获取文本
  2. 调用eval(thatScriptText)
  3. <script> DOM节点标记为已执行

当您克隆节点时,它也会得到内部的"executed"标志,从而阻止脚本进一步执行。

解决方案:如果您想重新执行脚本,请执行步骤#1和#2。在这种情况下不需要克隆。