获取字符串中 <body> </body> 标签内的内容

5
我想要做以下事情。
$("a").click(function (event) {

    event.preventDefault();

    $.get($(this).attr("href"), function(data) {

        $("html").html(data);

    });

});

我希望所有超链接的行为都可以进行ajax调用并获取html内容。
不幸的是,您不能简单地用ajax响应中接收到的html替换当前的html。
如何仅获取ajax响应中在标签内的内容,以便只替换现有html中body的内容。
编辑: 开始标记不总是只有 ,它可能有一个类,例如:

2
$("body").html() 有什么问题吗? - Thomas Shields
4
你为什么要“替换”身体的所有内容?(注意:这里有双关语) - Sujit Agarwal
我找到的最佳答案在这里:https://dev59.com/flDTa4cB1Zd3GeqPHTY3#3642850 - nabrown
3个回答

11

如果我理解正确,你可以使用正则表达式获取位于 body 标签之间的内容。

$.get($(this).attr("href"), function(data) {
    var body=data.replace(/^.*?<body>(.*?)<\/body>.*?$/s,"$1");
    $("body").html(body);

});

编辑

根据您下面的评论,这是一个更新,可以匹配任何body标签,无论其属性如何:

$.get($(this).attr("href"), function(data) {
    var body=data.replace(/^.*?<body[^>]*>(.*?)<\/body>.*?$/i,"$1");
    $("body").html(body);

});

正则表达式是:

^               match starting at beginning of string

.*?             ignore zero or more characters (non-greedy)

<body[^>]*>     match literal '<body' 
                    followed by zero or more chars other than '>'
                    followed by literal '>'

(               start capture

  .*?           zero or more characters (non-greedy)

)               end capture

<\/body>        match literal '</body>'

.*?             ignore zero or more characters (non-greedy)

$               to end of string

添加'i'开关以匹配大小写。

请忽略我的有关's'开关的评论,在JavaScript中,所有RegExp默认都是单行模式,要匹配多行模式,可以添加'm'。(该死的Perl,在我写有关JavaScript的文章时干扰我!:-)


1
我不认为那个正则表达式有效,我在body变量上做了一个console.log测试,它仍然返回所有的HTML内容,而不仅仅是在body标签内的内容。 - aprea
1
我忘了提到,<body> 标签不总是只有 <body>,有时会有一个类,例如 <body class="class1 class2">,你能否更新正则表达式以适应这种情况? - aprea
1
哇,感谢你详细的回复Rob,不幸的是我仍然无法让它工作。如果你在你的脚本中将$("body").html(body);更改为console.log(body);,然后在这个特定的stackoverflow页面上使用firebug运行脚本并点击某个超链接,你会发现它仍然返回从<html></html>的整个页面。 - aprea
1
@PeterV.Mørch确实如此,从清除分隔的、不重复的容器(如<head/>或<body/>)中提取内容与尝试提取深度嵌套的内容之间存在着根本性的区别。正则表达式是前者的完美解决方案,正如多次指出的那样,对于后者来说则不适用。 - Rob Raisch
1
@RobRaisch 我点赞了你的评论因为它有价值。然而,我的观点仍然没有变:正则表达式不能胜任这项工作。一个 <body> 可以包含一个带有 // </body> 注释的 <script> 标签。这在HTML5中是有效的,但会破坏上面的正则表达式。虽然正则表达式可以在一些(或大多数)HTML中起作用,但对于所有有效的 HTML <body> 标签,正则表达式无法可靠地完成此任务,因此我正在寻找更稳定的方法。 - Peter V. Mørch
显示剩余8条评论

1
我不想涉及正则表达式。相反,我创建了一个隐藏的<iframe>,将内容加载到其中,并从<iframe>中的页面中提取了<body>,在页面的onload()中进行操作。
我需要小心处理同源策略,以便使用iframe(这篇文章展示了方法):
var iframe = document.createElement('iframe');
iframe.style.display = "none";
jQuery('body').append(iframe);
iframe.contentWindow.contents = data;
iframe.onload = function () {
    var bodyHTML = jQuery(iframe).contents()
                        .find('body').html();
    // Use the bodyHTML as you see fit
    jQuery('#error').html(bodyHTML);
}
iframe.src = 'javascript:window["contents"]';

当你完成时,只需删除<iframe>标签即可...

-1
请务必将事件绑定到文档上,通过类进行过滤($(document).on('click', '.my-class-name', doThings);)。如果您替换了body的html,则直接完成的任何事件绑定($('.my-class-name').on('click', doThings);)将在使用新html重新绘制DOM时被销毁。重新绑定可以解决问题,但也会留下一堆指向旧事件和节点的指针,垃圾收集器必须清理它们--简单来说,这可能会使页面越来越重,打开时间越长。我没有在多个平台上测试过这个问题,请谨慎使用。
// create a new html document
function createDocument(html) {
  var doc = document.implementation.createHTMLDocument('')
  doc.documentElement.innerHTML = html
  return doc;
}
$("a").click(function (event) {
    event.preventDefault();
    $.get($(this).attr("href"), function(data) {
        $("body").html($(createDocument(data)).find('body').html);
    });
});

我本来很希望这个能够工作。但是 jQuery('<html><body>foobar</body></html>').find('body').length == 0 :-( 因此我要点踩。 - Peter V. Mørch
奇怪的是,jQuery('<div><span>foobar</span></div>').find('span').length == 1,但我无法从<html>中提取<body> - Peter V. Mørch
@PeterV.Mørch 我添加了一个函数来先创建一个新的 HTML 文档。这似乎有效 - 你可以确认一下吗? - Chris Baker

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