【问题标题】:Execution of dynamically generated Javascript执行动态生成的 Javascript
【发布时间】:2017-01-15 15:23:29
【问题描述】:

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

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

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

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

我可以看到正在执行的&lt;script&gt; 元素的注入代码(console.log() 函数输出测试)。

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

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

是什么促使了这种行为?

【问题讨论】:

    标签: javascript html dom properties innerhtml


    【解决方案1】:

    这在Scripting 中有描述。当脚本为prepared时,

    1. 在第 2 步,“parser-inserted”标志被移除:

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

    2. 在第 4 步,在恢复“parser-inserted”标志之前,这些步骤被中止

      如果元素没有src属性,其子节点,如果 任何,仅包含注释节点和空的Text 节点,然后 此时用户代理必须中止这些步骤。剧本不是 执行。

    因此,当你修改它时,它会再次准备:

    script 元素未被标记为 "parser-inserted" 经历了以下事件之一 以下列表,用户代理必须同步prepare script元素:

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

    如果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=""),它将无法工作。

      此外,在“动态”示例中,请注意innerHTMLsrc 值在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 时,我的脚本正在执行,这是我问题的全部重点 - 为什么会发生这种情况?
        • 因为它是空的。我不知道为什么。
        • 因为您正在编写自执行代码行,而不是必须单独调用的变量或函数。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-02-04
        • 2021-07-10
        • 2017-07-08
        • 1970-01-01
        相关资源
        最近更新 更多