在不运行html中脚本的情况下将html附加到jQuery元素

14

我编写了一些代码,使用jQuery来清除字符串中的丑陋HTML(在该SO问题中可以看到早期原型)。它工作得很好,但我遇到了一个问题:

当使用.append()将HTML包装在div中时,代码中的所有脚本元素都会被评估和运行(参见此SO答案以了解为什么会发生这种情况)。我不想这样做,我只是想让它们被删除,但只要它们不被运行,我就可以自己解决后面的处理。

我正在使用以下代码:

var wrapper = $('<div/>').append($(html));

我尝试以另外一种方式来实现:

var wrapper = $('<div>' + html + '</div>');

但这只会在IE中引发“拒绝访问”错误,而append()函数可以修复该问题(请参见我上面提到的答案)。

我认为我可能能够重写我的代码,使其不需要包装html,但我不确定,我想知道是否有可能附加html而不运行其中的脚本。

我的问题:

  • 如何包装未知的html片段,而不运行其中的脚本,最好是将其完全删除?

  • 我是否应该抛弃jQuery,改用普通JavaScript和DOM操作来实现?这样会有帮助吗?

我不打算做什么:

我不打算在客户端实现某种安全层。 我非常清楚这是毫无意义的。

更新:James的建议

James建议我应该过滤掉脚本元素,但是看看这两个示例(首先是原始文件,然后是James的建议):

jQuery("<p/>").append("<br/>hello<script type='text/javascript'>console.log('gnu!'); </script>there")

保留文本节点但输出"gnu!"

jQuery("<p/>").append(jQuery("<br/>hello<script type='text/javascript'>console.log('gnu!'); </script>there").not('script'))`

不写 gnu!而且还会丢失文本节点。

更新2:

James 更新了他的答案,我已经接受了。不过请看一下我对他的答案最新的评论。

3个回答

10

先把脚本移除,怎么样?

var wrapper = $('<div/>').append($(html).not('script'));

  • 创建 div 容器
  • 使用纯 JS 将 html 插入 div 中
  • 移除 div 中的所有 script 元素

假设 html 中的 script 元素未嵌套在其他元素中:

var wrapper = document.createElement('div');
wrapper.innerHTML = html;
$(wrapper).children().remove('script');

var wrapper = document.createElement('div');
wrapper.innerHTML = html;
$(wrapper).find('script').remove();

对于仅包含文本以及文本在任何元素之外的HTML情况,此方法有效。


好主意,它几乎可以工作,但还不够完美。我有一个字符串,有时会粗心地称之为html,它可能包含标签外的文本,我也想要这些文本。请参见我的更新答案以获取示例。 - Peter Jaric
此外,“html”可能只是文本,没有标签,如果将其发送到$()/jQuery(),jQuery将根据文档将其视为选择器:http://api.jquery.com/jQuery/#jQuery2 - Peter Jaric
而且 not() 只有在脚本未包含在另一个元素中时才起作用。 - bpierre
这很有前途!稍加修改似乎也适用于嵌套脚本:jQuery(wrapper).find('script').remove()。它在Chrome中有效,现在我会尝试在IE中使用(皱眉)。 - Peter Jaric
概念验证在IE中也可以工作。现在我将把它添加到我的真实代码中。 - Peter Jaric
显示剩余2条评论

0

尝试这段代码:jQuery("<div/>").append(jQuery("<br/>hello<script type='text/javascript'>console.log('gnu!'); </script>there").remove('script'))。实际上,它仍然运行脚本标签,并且只删除了一个文本节点...有趣... - Peter Jaric
是的,脚本在 $(html) 上执行... 看起来解决方案是使用正则表达式删除脚本元素? - bpierre
但那是邪恶的: https://dev59.com/X3I-5IYBdhLWcg3wq6do#1732454 :) - Peter Jaric
是的,你需要一个真正的解析器,像json2.js一样强大,但是用于删除脚本标签 :-) - bpierre

0

在这里提到的所有简单方法都无法停止html中的脚本执行,然后我想起jquery有一个工具可以做到这一点(自1.8版本以来),jQuery.parseHTML。但仍有一个问题,根据文档,属性内的事件(例如<img onerror>)仍将运行。

这是我正在使用的:

var $dom = $($.parseHTML(d));
$dom将是一个包含找到的元素的jQuery对象。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接