执行动态生成的 Javascript
Posted
技术标签:
【中文标题】执行动态生成的 Javascript【英文标题】:Execution of dynamically generated Javascript 【发布时间】:2017-01-15 15:23:29 【问题描述】:我正在阅读this 问题,接受的答案是:
通过设置元素的 innerhtml 属性添加的脚本不会被执行。
但是当我尝试在以下代码中更改第一个 <script>
标记的 innerHTML 时:
<script></script>
<script>
document.querySelectorAll("script")[0].innerHTML = 'console.log("Test")';
</script>
我可以看到正在执行的<script>
元素的注入代码(console.log()
函数输出测试)。
此外,如果我删除第一个空的 <script>
标记(从而使第一个元素 [0]
引用脚本本身),则脚本在 DOM 中被更改,但代码永远不会执行。
<script>
document.querySelectorAll("script")[0].innerHTML = 'console.log("Test")';
</script>
是什么促使了这种行为?
【问题讨论】:
【参考方案1】:这在Scripting 中有描述。当脚本为prepared时,
在第 2 步,“parser-inserted”标志被移除:
如果元素设置了"parser-inserted" 标志,则设置 was-parser-inserted 为 true 并取消设置元素的 "parser-inserted" 标志。
在第 4 步,在恢复“parser-inserted”标志之前,这些步骤被中止
如果元素没有
src
属性,其子节点,如果 任何,仅包含注释节点和空的Text
节点,然后 此时用户代理必须中止这些步骤。剧本不是 执行。
因此,当你修改它时,它会再次准备:
当
script
元素未被标记为 "parser-inserted" 经历了以下事件之一 以下列表,用户代理必须同步preparescript
元素:script
元素得到inserted into a document,当时根据 DOM,node is inserted,在任何 同时插入的其他script
元素 早在Document
中tree order。script
元素是in aDocument
,一个节点或文档片段是inserted 到script
元素中, 在当时的任何script
元素inserted 之后。script
元素是 in aDocument
并且有一个src
属性集,而以前该元素没有这样的属性 属性。
脚本运行后,修改内容不会执行,因为脚本准备会中止:
如果
script
元素被标记为具有"already started",那么用户代理必须在此中止这些步骤 观点。脚本未执行。
【讨论】:
【参考方案2】:确实非常有趣的发现!
空的 src-less script
元素似乎处于某种奇怪的状态,它接受内容甚至新的 src
并解释它们。 (也找不到原因。我只是有一个小小的提示:)
它类似于动态插入脚本元素的行为。
这是您观察的示例/证明,并添加了更多案例以供说明:
script[src]::before,
script
display: block;
border: 1px solid red;
padding: 1em;
script[src]::before,
script
content: 'src='attr(src)
button
display: block
<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>
您必须重新运行 sn-p 才能看到两种“静态”情况都有效。
(还有一个包含由 SO 生成的空白的空白脚本,无论出于何种原因。)
正如 Laurianti 所展示的,如果脚本有一些(甚至是空白)内容(或 src=""
),它将无法工作。
此外,在“动态”示例中,请注意innerHTML
或src
值在script
元素插入文档后 发生了更改。因此,可以有一个空白的静态或创建动态脚本,将其留在文档中并设置使用它很久之后。
很抱歉没有给出完整的答案,只是想分享研究和提示。
(更新已删除;Oriol 更快、更准确。唷,很高兴看到这个问题解决了!)
【讨论】:
【参考方案3】:如果你改变了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>
【讨论】:
但是当我更改 innerHTML 时,我的脚本正在执行,这是我问题的全部重点 - 为什么会发生这种情况? 因为它是空的。我不知道为什么。 因为您正在编写自执行代码行,而不是必须单独调用的变量或函数。以上是关于执行动态生成的 Javascript的主要内容,如果未能解决你的问题,请参考以下文章