【问题标题】:Why does replacing the <body> tag in an iframe cause an additional <head> tag to be added?为什么替换 iframe 中的 <body> 标签会导致添加额外的 <head> 标签?
【发布时间】:2015-03-07 08:29:32
【问题描述】:

我遇到了一个我找不到解释的有趣问题。将 iframe(同源)中的 &lt;body&gt; 标记替换为 iframe.document.body.outerHTML = content; 时,会在 iframe 中添加一个额外的空 &lt;head&gt; 标记。这种行为在 Chrome 和 Firefox 中是相同的(我没有测试过 Safari 或 IE。)以下示例显示了问题,只需检查 iframe 以查看添加的 &lt;head&gt; 标记。

http://jsfiddle.net/8huj4fxs/

<!doctype html>
<html>
  <head>
    <title>iframe problem</title>
  </head>
  <body>
    <iframe id="iframe"></iframe>

    <script type="text/javascript">
      var html = '';
      html += '<!doctype html>';
      html += '<html>';
      html += '<head><style type="text/css">h1 { color: red; }</style></head>';
      html += '<body><h1>Title</h1></body>';
      html += '</html>';

      var iframe = document.getElementById('iframe').contentWindow.document;
      iframe.open();
      iframe.write(html);
      iframe.close();

      for(var i = 0; i < 5; i++) {
        content = '<body><h1>Title '+ i +'</h1></body>';

        document.getElementById('iframe').contentWindow.document.body.outerHTML = content;
      }
    </script>
  </body>
</html>

【问题讨论】:

  • 看起来很有趣。有什么后果吗? document.head 好像是指第一个,也就是原文。
  • 我还没有发现任何功能问题。我确信它会弄乱一些只需要一个 的脚本,因为它显然是无效的 HTML。我的强迫症真的在这里杀了我。
  • 我删除了我的答案,因为我认为这是错误的。我想我错过了上下文节点应该已经有一个头标签,因此片段解析器将跳过添加一个。对此感到抱歉。
  • 好的我已经看这个太久了,浏览了铬源代码,我不确定我错了,所以我把答案放回去了,供讨论最少。

标签: javascript html dom iframe


【解决方案1】:

我将把它备份起来,至少是为了进一步讨论,因为我认为我最初的推理可能是正确的。我认为 3 的 16.1 中引用的 head 元素指针 在这种情况下可能始终为 null,从而导致添加了 &lt;head&gt; 元素。

原答案

这似乎是一个有趣的研究问题......如果我正确解释了规范,这似乎是正在发生的事情:

tl;dr: 当解析具有&lt;html&gt;&lt;body&gt; 的父级)上下文的片段时,如果片段不包含&lt;head&gt;,则为空片段自动包含。

相关规范:

  1. outerHTML
  2. Parsing HTML fragments
  3. Reset the insertion mode appropriately
  4. Before Head insertion mode

根据outerHTML 规范,当您设置此属性时,您会在片段中启动浏览器解析。解析片段可以传递一个上下文元素。在outerHTML 的情况下,上下文被设置为设置了outerHTML 的元素的父元素,在这种情况下,它是&lt;iframe&gt;&lt;body&gt; 元素的父元素,它的&lt;html&gt; 元素。

在解析输入时,在您的情况下为'&lt;body&gt;&lt;h1&gt;Title '+ i +'&lt;/h1&gt;&lt;/body&gt;',片段解析器首先创建一个新文档并将&lt;html&gt; 元素作为根元素附加到它。然后,解析器的插入模式得到set according to the context。上下文是一个&lt;html&gt; 元素,因此根据3 的步骤16.1 将插入模式设置为'before head'。然后根据2 的第 6 步,使用您的 outerHTML 输入运行解析器。它首先遇到的是&lt;body&gt; 标签,根据4,这意味着&lt;head&gt; 标签被插入到文档中,然后继续解析你输入的其余部分。

完成后,根据2,将返回根节点的所有子节点,除了您的输入之外,还包括一个空的&lt;head&gt; 标记,并插入到文档中以代替&lt;body&gt; 元素outerHTML 已更改。

希望这会有所帮助!

【讨论】:

  • 所以这可能被认为是规范中的一个错误,除非浏览器应该在应该只有一个的基础上删除额外的头部。
  • 可能是。似乎在解析片段时,如果上下文元素是 &lt;html&gt; 标记,您会想要检查它是否有 &lt;head&gt; 子元素,而不是检查解析器是否已经读入 @ 987654348@ 标签。不确定...
  • 听起来不错。如果我使用原始小提琴但更改循环以将outerHTML 设置为'&lt;head&gt;&lt;/head&gt;&lt;body&gt;&lt;h1&gt;Title '+ i +'&lt;/h1&gt;&lt;/body&gt;',那么我会得到与原始小提琴相同数量的正面。为什么?因为浏览器不需要创建新的head元素。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-01-14
  • 1970-01-01
  • 2012-04-21
  • 2011-09-12
  • 2016-05-06
  • 2017-06-10
  • 2011-07-31
相关资源
最近更新 更多