【问题标题】:Why does browsers parse <script> tags differently?为什么浏览器解析 <script> 标签的方式不同?
【发布时间】:2019-09-12 03:39:15
【问题描述】:

我正在开发一个新网站,在编写一些客户端 HTML/Javascript 代码时,我遇到了这种情况。

如果&lt;script&gt; 标记中有 HTML 编码字符,例如 &lt;script&gt; alert("&amp;gt;");&lt;/script&gt;,则必须弹出带有 &amp;gt; 的警报,因为我相信 HTML 解析器在 @987654326 的 javascript 解析器之前首先运行@ 和 &lt;style&gt; 标签。这按预期工作。

现在,在编写一些代码时,我这样做了 - &lt;svg&gt;&lt;script&gt;alert("&amp;gt;");&lt;/script&gt;&lt;/svg&gt;。这次我得到一个带有&amp;gt; 而不是&amp;gt; 的弹出窗口。虽然我可以理解是因为&lt;svg&gt; 标签,但我不确定根本原因是什么以及除了&lt;svg&gt; 之外的其他标签会改变默认行为。

如果有人可以指出官方文档,那将非常有帮助。

这是我为这个场景创建的一个简单的 JSFiddle - https://jsfiddle.net/emz8Lfxt/

【问题讨论】:

  • 您的 HTML 无效。您的 SVG 标记未关闭,现在浏览器会混淆 SVG 是在脚本标记周围(顺便说一句,这没有任何意义)还是在它之前。关闭您的 SVG 标签,看看是否有不同的工作方式。您可以使用此站点验证您的 HTML 是否有效。 validator.w3.org/#validate_by_input
  • 关闭 svg 标签对用户演示的内容没有影响。自己试试。我会注意到我赞成他的问题来反驳你的反对票;不管一些无关紧要的复制粘贴,这个问题都很有趣。
  • @Crayons - 谢谢!在 标签之后关闭 svg 标签没有影响。
  • 在脚本标签之前或之后关闭标签确实会有所不同。
  • &lt;svg&gt;&lt;/svg&gt;&lt;script&gt;&lt;/script&gt;&lt;svg&gt;&lt;script&gt;&lt;/script&gt;&lt;/svg&gt; 确实有所作为。

标签: javascript html xml svg


【解决方案1】:

HTML 文档中的内联 SVG 被解析器视为foreign element。然后它的内容被 SVG 解析器解析,这个 SVGElement 的所有内容都因此被解析为 SVG。

SVG 有 its own definition

<svg>
  <script>
    const thisScript = document.currentScript;
    console.log('HTMLScriptElement?', thisScript instanceof HTMLScriptElement); // false
    console.log('SVGScriptElement?', thisScript instanceof SVGScriptElement); // true
  </script>
</svg>

现在关于为什么 &lt;svg:script&gt; 元素的内容在执行之前会像 XML 一样被解析,我们需要及时回顾一下。

SVG1.1 did define

分类:

内容模型:
任何元素或字符数据。
属性:...

这意味着 SVG1.1 与 HTML 不同,它允许其

SVG tiny 1.2 从那时起就跟随 HTML 并将

[但是传入的 SVG2](https://www.w3.org/TR/SVG/interact.html#ScriptElement 应该在此处跟进,虽然它仍在讨论中,这意味着在不久的将来,我们不需要再将代码包装在 //&lt;![CDATA[ 块中,即使它会适合您的情况的解决方案:

<svg>
  <script>
    console.log("out", "&gt;"); // >
  //<![CDATA[ 
    // ^- this forces the SVG parser to treat the content as Character Data
    console.log("in", "&gt;"); // &gt;
  //]]>
  </script>
</svg>

但请注意,HTML 中不允许使用 &lt;![CDATA[ 块(因此是 // js cmets),除了 外来元素,例如 SVG 和 MathML,因此,您可能还只是想要将脚本移出 元素,使其直接成为 HTML 文档的一部分。

【讨论】:

    【解决方案2】:

    说实话,我觉得你很难找到关于为什么会发生这种情况的官方文档。

    在这种情况下,我最好的猜测是,由于 SVG 元素是 SVG 图形的容器,并且 SVG 容器是基于 XML 的,并且可以在其中包含其他 HTML 元素;示例:

    <svg>
        <rect style="fill:rgb(0,0,255);" />
    </svg>
    

    浏览器尝试解析内部 html,以绘制对象。但是,一旦它意识到它不是真正的 SVG 元素,它就会停止并继续执行您已经获得的 javascript。因此,&amp;gt; 在 javascript 最终被执行之前被解析。

    我觉得我们需要对如何处理 SVG 元素的细节有深入了解的人。

    我会记下这个示例,以供参考:

    <script>alert("&gt;")</script>
    <svg><script>alert("&gt;")</script></svg>
    <span><script>alert("&gt;")</script></span>
    

    将按顺序输出:

    &gt;
    >
    &gt;
    

    【讨论】:

    • 这很有意义。阅读完 W3 文档后,我倾向于您的答案。 :)
    【解决方案3】:

    浏览器特别解析&lt;script&gt;,它们不会替换其中的HTML实体。这使您可以编写如下内容:

    if (a < b)
    

    而不必写:

    if (a &lt; b)
    

    在早期的浏览器中,您必须编写如下内容:

    <script type="text/javascript">
    <![CDATA[
      …
    ]]>
    </script>
    

    CDATA 部分没有执行实体替换,因此您可以在其中“正常”编写代码。

    但后来的 HTML 规范将其设为 &lt;script&gt; 正文的默认值,因此不再需要。

    但是当&lt;script&gt;&lt;svg&gt; 中时,显然SVG 解析器优先。所以&amp;gt; 被翻译成&gt;

    【讨论】:

    • 除了&lt;svg&gt;之外,还有其他标签可以在&lt;script&gt;标签中解析HTML实体吗?
    • 我不知道。正如另一个答案中提到的,这显然是因为 SVG 本质上是它自己的迷你语言(使用 XML 语法),并且它必须完全解析它的主体。如果有任何其他标签定义了嵌入式语言,它们也可能会做同样的事情。
    • 顺便说一句,&lt;script&gt; 本身是另一个导致其内容被特别解析的标签——在这种情况下,它查找嵌入的标签和 HTML 实体。
    • 正如这篇文章所解释的,如果您在脚本标签中添加&lt;![CDATA[ … ]]&gt;,您将能够像往常一样解析它们:jsfiddle.net/sob43r2v(可能相关来源:dev.w3.org/SVG/tools/svgweb/docs/QuickStart.html
    猜你喜欢
    • 1970-01-01
    • 2012-10-01
    • 1970-01-01
    • 2012-03-09
    • 2021-11-22
    • 2012-02-18
    • 2011-04-01
    • 1970-01-01
    • 2019-09-30
    相关资源
    最近更新 更多