执行动态生成的Javascript

时间:2016-09-07 20:16:37

标签: javascript html dom properties innerhtml

我正在阅读this问题,接受的答案是:

  

通过设置元素的innerHTML属性添加的脚本不会被执行。

但是当我尝试更改以下代码中第一个<script>标记的innerHTML时:

<script></script>
<script>
document.querySelectorAll("script")[0].innerHTML = 'console.log("Test")';
</script>

我可以看到正在执行的<script>元素的注入代码(console.log()函数输出Test)。

此外,如果我删除第一个空<script>标记(从而使第一个元素[0]引用脚本本身),则在DOM中更改脚本,但代码永远不会执行。< / p>

<script>
document.querySelectorAll("script")[0].innerHTML = 'console.log("Test")';
</script>

是什么促使这种行为?

3 个答案:

答案 0 :(得分:4)

Scripting中对此进行了描述。当脚本为prepared时,

  1. 在第2步,&#34;解析器插入&#34;标志被删除:

      

    如果元素设置了"parser-inserted"标志,则设置    is-parser-inserted 为true并取消设置元素的"parser-inserted"标记。

  2. 在第4步,恢复&#34;解析器插入&#34;标志,步骤被中止

      

    如果元素没有src属性及其子节点if   any,只包含注释节点和空Text个节点   用户代理必须在此时中止这些步骤。脚本不是   执行。

  3. 因此,当您修改它时,它将再次准备好:

      

    script元素未标记为时   "parser-inserted"遇到了一个列出的事件   在以下列表中,用户代理必须同步prepare   script元素:

         

    脚本运行后,修改内容不会执行它们,因为脚本准备将中止:

      

    如果"already started"元素标记为{{3}},则用户代理必须在此处中止这些步骤   点。该脚本未执行。

答案 1 :(得分:2)

非常有趣的发现!

似乎空src-less script元素处于一种奇怪的状态,它接受内容甚至是新的src并解释它们。 (也无法找到原因。我只是有一个小小的暗示:)

类似于动态插入的脚本元素的行为。

以下是您观察的示例/证据,并添加了更多案例以供说明:

&#13;
&#13;
script[src]::before,
script {
  display: block;
  border: 1px solid red;
  padding: 1em;
}
script[src]::before,
script {
  content: 'src='attr(src)
}
button {
  display: block
}
&#13;
<p>Existing empty script in HTML:</p>
<script id="existing"></script>
<p>Can be invoked just one of:</p>
<button onclick="eval(this.innerText)">
  existing.innerHTML='console.log("innerHTML to static")'
</button>
<button onclick="eval(this.innerText)">
  existing.src='data:text/javascript,console.log("src to static")'
</button>
<p>Dynamically created and inserted script (each creates own, so both work):</p>
<button onclick="eval(this.innerText)">
  document.body.appendChild(document.createElement('script')).innerHTML='console.log("innerHTML to dynamic")'
</button>
<button onclick="eval(this.innerText)">
  document.body.appendChild(document.createElement('script')).src='data:text/javascript,console.log("src to dynamic")'
</button>
&#13;
&#13;
&#13;

您必须重新运行代码段以查看&#34;静态&#34;案件有效。

(还有一个包含由SO生成的空白的空白脚本,无论出于何种原因。)

正如Laurianti所展示的那样,如果脚本有一些(甚至是空白的)内容(或src=""),那么它就行不通了。

此外,在&#34;动态&#34;示例请注意,{/ 1}}或innerHTML值在 src元素插入文档后被更改。因此可以使用空白静态或创建动态脚本,将其保留在文档中并在此之后设置使用它。

很抱歉没有给出完整的答案,只是想分享研究和提示。

(更新删除; Oriol更快,更准确.Phew,很高兴看到这个整理好了!)

答案 2 :(得分:0)

如果更改innerHTML,则不会执行。你必须在追加它之前和之后写它。

    var script = document.createElement("script");
    script.innerHTML = 'console.log("Test");';
    document.getElementsByTagName('head')[0].appendChild(script);

尝试添加新行:

<script>
</script>
<script>
document.querySelectorAll("script")[0].innerHTML = 'console.log("Test")';
</script>