【问题标题】:Get contents of <body> </body> within a string获取字符串中 <body> </body> 的内容
【发布时间】:2011-09-05 22:34:04
【问题描述】:

我想做以下事情。

$("a").click(function (event) {

    event.preventDefault();

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

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

    });

});

我希望所有超链接的行为都能进行 ajax 调用并检索 html。

不幸的是,您不能简单地将当前的 html 替换为您在 ajax 响应中收到的 html。

如何只抓取 ajax 响应的 &lt;body&gt; &lt;/body&gt; 标记内的内容,以便我可以替换 only 现有 html 中正文的内容。

编辑:&lt;body&gt; 开始标签并不总是只是 &lt;body&gt; 它有时可能有一个类,例如

&lt;body class="class1 class2"&gt;

【问题讨论】:

  • $("body").html() 有什么问题?
  • 为什么要替换 BODY 的所有内容? 双关语

标签: jquery html ajax


【解决方案1】:

如果我理解正确,请使用正则表达式获取正文标签之间的内容。

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

});

编辑

根据您在下面的 cmets,这里有一个更新以匹配任何 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 的时候干扰我!:-)

【讨论】:

  • 我不认为正则表达式有效,我在 body 变量上做了一个 console.log,它仍然返回所有的 html,而不仅仅是 body 标签中的内容。
  • 运行以下代码:var page=' foobody'; page.replace(/^.*?(.*?).*?$/, "$1");提供:“body”作为其答案。
  • 我忘了提,&lt;body&gt; 标签并不总是&lt;body&gt; 它有时会有一个类,&lt;body class="class1 class2"&gt; 你是否可以更新正则表达式以适应这个?
  • 哇,谢谢你的详细回复 rob,不幸的是我仍然无法让它工作。如果您将脚本中的$("body").html(body); 更改为console.log (body);,然后在此特定stackoverflow 页面上的firebug 中运行脚本并单击某处的超链接,您会看到它仍将整个页面从&lt;html&gt; 返回到&lt;/html&gt;
  • @PeterV.Mørch 确实,但是在提取诸如&lt;head/&gt;&lt;body/&gt; 之类的清除分隔的非重复容器的内容与尝试提取深度嵌套的内容之间存在巨大差异。 Regexen 是前者的完美解决方案,但正如多次指出的那样,不适合后者。
【解决方案2】:

我不想弄乱正则表达式。相反,我创建了一个隐藏的&lt;iframe&gt;,加载了其中的内容,然后从页面的&lt;iframe&gt; 中的&lt;iframe&gt; 中提取了&lt;body&gt;

我需要小心 Same-origin policy 的 iframe(这个 article 显示了方式):

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"]';

完成后删除&lt;iframe&gt;...

【讨论】:

    【解决方案3】:

    确保将事件绑定到文档,按类过滤($(document).on('click', '.my-class-name', doThings);)如果替换正文的 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('&lt;html&gt;&lt;body&gt;foobar&lt;/body&gt;&lt;/html&gt;').find('body').length == 0 :-( 出于这个原因,我不赞成。
    • 很奇怪,jQuery('&lt;div&gt;&lt;span&gt;foobar&lt;/span&gt;&lt;/div&gt;').find('span').length == 1,但我无法从&lt;html&gt; 中提取&lt;body&gt;
    • @PeterV.Mørch 我在那里添加了一个函数来首先制作一个新的 html 文档。这似乎有效——你能确认一下吗?
    猜你喜欢
    • 1970-01-01
    • 2023-03-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多