【问题标题】:jQuery's attr() function breaks html with html special characters?jQuery 的 attr() 函数用 html 特殊字符破坏 html?
【发布时间】:2012-12-12 19:50:37
【问题描述】:

请看下面的代码:

http://jsfiddle.net/htdTg/2/

在第一个链接中有一个标题属性,其中包含 html 特殊字符 < 后跟“!” (实际上跟在哪个字符后面并不重要)。 当我们使用 jQuery 的 attr() 函数获取该标题属性的值时,html 被破坏(您可以看到,只要以下文本也丢失,就没有打印“

在第二个链接中,唯一的区别是我在< 之后添加了一个空格,现在它可以按预期工作了。

您认为这是 jQuery 中的错误还是我只是不明白?

PS。如果您认为我在做一些奇怪的事情 - 这只是来自某个工具提示插件的一段代码。

HTML:

<a href="#" title="<div style='color:red'>This is the less than sign: &lt;! Now you know it?</div>">This is a link</a><br>
<a href="#" title="<div style='color:red'>This is the less than sign: &lt; ! Now you know it?</div>">This is a link</a><br>​

jQuery:

$('a').each(function() {
    $('body').append($(this).attr('title')); });

// just to exclude that it's append() function's fault :)
$('body').append("<div style='color:red'>This is the less than sign: &lt;! Now you know it?</div>");​

【问题讨论】:

  • 属性中包含HTML代码是否有效?
  • 我从 jsFiddle 添加了您的代码。关于 SO 的问题和答案应该是完全“独立的”。
  • 标题不应包含任何 HTML。有些人确实会悬停链接,然后查看代码。
  • 您看到 W3C 标准了吗?看我的回答stackoverflow.com/a/13847609/376535
  • @ErikE: 在属性中包含 escaped 代码是有效的。

标签: javascript jquery html


【解决方案1】:

这很有趣。我查看了 title attribute 中可以包含哪些文本,参考文献中说:

用户代理应该如下解释属性值:

  1. 用字符替换字符实体,
  2. 忽略换行,
  3. 用一个空格替换每个回车符或制表符。

显然,这是预期的行为。 &amp;lt; 正在被浏览器解析为 &amp;lt;,这可能会被 jQuery 解释为 HTML。

您也应该转义与号:

&amp;lt;

演示:http://jsfiddle.net/htdTg/9/

更好的演示:http://jsfiddle.net/PsZeY/6/

【讨论】:

  • 如果您要转义属于有效字符实体编码一部分的 & 符号,那么如何将 & 符号作为字符实体编码的一部分放入其中?
  • 但是你有一个未转义的&符号。所以你应该做&amp;amp;amp;amp;amp;amp;amp;lt;。但是,还是逃不过!所以&amp;amp;amp;amp;amp;amp;amp;lt;。等等--&amp;amp;amp;amp;amp;amp;amp;lt;。不,&amp;amp;amp;amp;amp;amp;amp;lt;。啊!问题是为什么双重转义?如果规则是,如您所说,Replace character entities with characters,那么&amp;lt; 怎么会不工作? 它被逃脱了。
  • @ErikE:不是真的。浏览器在解析 HTML 时将字符实体替换为其各自的字符。您只是转义两次,因此您检索的值是两次转义代码的未转义版本,它只转义一次。
  • @ErikE:想解释一下如何?我从来不需要将 HTML 放入工具提示中,所以我不知道为什么您需要这样做,但这样做本身并没有什么问题。
  • @ErikE:这不是问题的重点。问题是为什么属性的值在从解析器传递到脚本或样式表时会发生变化。即使您“正确”地执行此操作,也会出现同样的问题:jsfiddle.net/htdTg/13
【解决方案2】:

为什么会这样?

这是因为&amp;lt;! Now you know it? &lt;/div&gt; 被转换为&lt;! Now you know it? &lt;/div--&gt;

根据 HTML 标准&amp;lt;!&gt;评论结构 的开始和结束。请注意,这是评论结构不是评论。因此,浏览器将其余部分转换为注释,除非它得到一个结束分隔符 &gt;

来自W3C

<!-- this is a comment -->
<!-- and so is this one,
    which occupies more than one line -->

标记声明打开分隔符(&amp;lt;!)和评论打开分隔符(--)之间不允许有空格,但评论关闭分隔符(--)之间允许有空格和 标记声明关闭 分隔符 (">")。一个常见的错误是在评论中包含一串连字符 (---)。作者应避免在 cmets 中放置两个或多个相邻的连字符。

同样在here

SGML 中注释声明的语法是

 comment declaration =
    MDO ("<!"), (comment, ( s | comment )* )?, MDC (">")
 comment =
    COM ("--"), SGML character*, COM ("--")

如何解决?

你已经知道了。使用&amp;amp; 替换&amp;。所以写&amp;amp;lt;!而不是&amp;lt;!。这将使&amp;lt; 附加到正文元素而不是&amp;lt;!,这是打开注释结构。

【讨论】:

  • 问题不在于如何让它发挥作用,而是为什么在目前的形状和形式下它不会。
  • @KingKongFrog 添加了为什么
  • 你仍然没有回答最终的为什么——你回答了&amp;lt;!开始HTML评论的大致原因。但是为什么需要对属性进行双重编码呢?这只是因为 OP 将 HTML 塞进了一个不属于它的地方。
【解决方案3】:

在这种情况下...

title="<div style='color:red'>This is the less than sign: &lt;! Now you know it?</div>"

&amp;lt;! 被转换为 &lt;!,这是 HTML 注释的开头,这正是它不在浏览器窗口中呈现的原因。

在所有情况下,您都不应该在属性中包含 HTML 实体。改用这个...

title="&lt;div style='color:red'&gt;This is the less than sign: &amp;lt;! Now you know it?&lt;/div&gt;"

http://jsfiddle.net/htdTg/5/

如果您想保留 HTML 实体,请将&amp;amp;lt;div&amp;amp;gt; 用作&lt;div&gt; 进行处理。或者,&amp;amp;lt;div&amp;amp;gt; 实际上会渲染 &lt;div&gt; 在浏览器窗口中。

见:http://jsfiddle.net/htdTg/8/

因此,如果您希望浏览器实际显示&lt;!,请使用:&amp;amp;lt!

【讨论】:

  • 所以,为了安全起见,如果以编程方式编码属性,不应该所有&amp;amp;lt; 字符都是&amp;amp;lt; 吗?跟随实体的角色可以决定该实体的表示方式,这真是令人讨厌。
  • @ErikE,这取决于你想要做什么。在这里查看区别:jsfiddle.net/htdTg/8
  • 您回答了问题,但没有解决更重要的问题,即 OP不应该这样做
  • @ErikE,嗯?也许你错过了这条线? “在所有情况下,您都应该在属性中包含 HTML 实体”
  • 我关心的不是“如何转义实体”,而是“将 HTML 放入标题属性中,无论是否转义”。
【解决方案4】:

文本没有遗漏问题是它被评论了,因为&amp;lt;!&lt;! 相同,后者正在被翻译为&lt;!--(不知道为什么),它在html 中开始评论.

如果您检查 html,您将看到以下内容。

<div style='color:red'>This is the less than sign: <!-- Now you know it? --></div>
<div style='color:red'>This is the less than sign: < ! Now you know it?</div> 

【讨论】:

    【解决方案5】:

    我不确定您是只是提出问题还是实际上正在寻找问题的解决方案。如果是后者,那么奇怪的是这似乎工作正常:&amp;amp;lt;

    更新代码:

    HTML:

    <a href="#" title="<div style='color:red'>This is the less than sign: &amp;lt;! Now you know it?</div>">This is a link</a><br>
    <a href="#" title="<div style='color:red'>This is the less than sign: &amp;lt; ! Now you know it?</div>">This is a link</a><br>​
    

    jQuery:

    $('a').each(function() {
        $('body').append($(this).attr('title')); });
    
    // just to exclude that it's append() function's fault :)
    $('body').append("<div style='color:red'>This is the less than sign: &lt;! Now you know it?</div>");​
    

    更新小提琴:http://jsfiddle.net/htdTg/3/

    【讨论】:

    • 那么它在我看来就像 jQuery 中的一个错误。请尝试归档并链接到问题。我想看看官方的回复。
    • @JanDvorak,你可以随时去 IRC 频道问问自己;)
    • 没有 jQuery 错误。它使用 text 作为 HTML 这就是问题所在。
    【解决方案6】:

    没有什么是真的错了..

    问题是必须对属性内部的 html 进行编码。您已经将&amp;lt; 编码为&amp;lt;,这意味着它将被读取为&amp;lt;

    所以.attr() 将返回一个纯&amp;lt; 字符,而不是编码的..

    它不显示的原因是 .append 如果它认为其中有 html,它将尝试解析 html。它找到 &lt;! 文本并将其视为 html 注释。 实际上这是由浏览器直接完成的


    如果你看

    var e = document.createElement('div');
    e.innerHTML = '<!';
    console.log(e.innerHTML);
    

    你会看到设置为&lt;!后的div的内部HTML是&lt;!----&gt;

    这就是浏览器解释这段代码的方式..它与jQuery无关..

    【讨论】:

    • +1 获取append 信息。我进行了调查,它确实发生在append
    • 你知道为什么&lt;! 被认为是评论的开始吗?
    • @RicardoLohmann 因为 html cmets 以 &lt;!-- 开头并以 --&gt; 结尾。浏览器会将&lt;! 翻译为评论。更新答案以显示示例
    猜你喜欢
    • 2017-07-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多