5

我正在通过加载页面$.ajax()并将部分结果插入页面的相应部分:

$.ajax({
  url: '/whole_page.html',
  success: function (data, status, xhr) {
    $result = $(xhr.responseText);
    $('#menu').html($('#menu', $result).html());
    $('#content').html($('#content', $result).html());
  }
});

像魅力一样工作,但我遇到了问题。

现在我的页面包含一些特定于页面的 JS,这些 JS 必须在获取和插入结果时执行。据我所知,如果你从 HTML 文本构造一个 jQuery 对象并对其进行查询,jQuery 不会返回script元素(我做了一个小提琴来演示)。因此,我无法通过 jQuery 选择性地仅插入我想要的脚本。

所以看起来我必须script自己从响应文本中提取元素。本质上,我正在寻找正确的方法来做到这一点。到目前为止,这是我想出的:

function pullScripts(text) {
  var frag = document.createDocumentFragment()
    , div = document.createElement('div')
    , scriptElements
    ;

  // This is roughly how jQuery finds the scripts when cleaning text
  frag.appendChild(div);
  div.innerHTML = text;

  scriptElements = div.getElementsByClassName('class-for-scripts-that-we-want');

  $('head').append(scriptElements);
}

这工作得很好,虽然我还没有在任何糟糕的浏览器上测试过它。无论如何,为了避免它的一个特性(特殊script处理)而复制 jQuery 的这种基本功能感觉不舒服。从小提琴中可以看出,jQuery 对象实际上确实包含scripts,但它不会用类似.html()or的东西返回它们.get()我错过了一些明显的方法吗?

注意:一旦 jQuery 的内部parseHTML函数被暴露,这整个话题就没有实际意义了

注意 2:我还阅读了 Trying to select script tags from a jQuery ajax get response但是接受的答案是“你不能”,然后是“使用正则表达式”。这两个都不满意

4

3 回答 3

3

在 jQuery 1.8.0b1 中,您现在可以使用该$.parseHTML()方法来简化此操作。

$.parseHTML(xhr.responseText,true)将为您提供一个包含脚本元素的 jQuery 对象。然后,您可以提取脚本标签并在附加 html 后附加或执行它们。

$.ajax({
  url: '/whole_page.html',
  success: function (data, status, xhr) {
    var $result = $.parseHTML(xhr.responseText,true),
        $scripts = $result.find("script").add($result.filter("script")).detach();

    $('#menu').html($('#menu', $result).html());
    $('#content').html($('#content', $result).html());
    $('head').append($scripts);
  }
});

您可能必须过滤脚本以避免根据具体情况重复包含 jQuery。这取决于您正在加载的内容。

如果升级 jQuery 不是一个选项,您可以将$.parseHTML其作为插件包含到您当前的 jQuery 中

(function($) {
    if (!$.parseHTML) {
        var rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>)?$/;
        // data: string of html
        // context (optional): If specified, the fragment will be created in this context, defaults to document
        // scripts (optional): If true, will include scripts passed in the html string
        $.parseHTML = function( data, context, scripts ) {
            var parsed;
            if ( !data || typeof data !== "string" ) {
                return null;
            }
            if ( typeof context === "boolean" ) {
                scripts = context;
                context = 0;
            }
            context = context || document;

            // Single tag
            if ( (parsed = rsingleTag.exec( data )) ) {
                return [ context.createElement( parsed[1] ) ];
            }

            parsed = jQuery.buildFragment( [ data ], context, scripts ? null : [] );
            return jQuery.merge( [],
                (parsed.cacheable ? jQuery.clone( parsed.fragment ) : parsed.fragment).childNodes );
        }
    }
})(jQuery);
于 2012-07-09T18:09:25.300 回答
2

当我昨晚在 jsFiddle 上玩 jQuery (edge) 时,我无法.find()$.parseHTML(). 问题是它$.parseHTML返回一个元素数组而不是一个 jQuery 对象,如果你用你做一个,$()你又回到了原来的问题。所以,你仍然不能真正使用选择器。不过也不是很麻烦:

$.ajax({
  url: '/some_page.html',
  success: function (data, text, xhr) {
    var result = $.parseHTML(data, true)
      , scripts = []
      , i;

    // filter the scripts somehow
    for (i = 0; i < result.length; i++) {
        if (result[i].getAttribute('class') === 'good') {
            scripts.push(result[i]);
        }
    }

    $('head').append(scripts);
  }
});​

我为此做了一个工作小提琴

于 2012-07-10T16:37:05.707 回答
0

如前所述,您应该使用返回节点数组的 $.parseHTML。

我在应该附加在 ajax 请求上的脚本标记上添加了类 'append-on-ajax-script'。

我也遇到了 getAttribute('class') 函数的问题,所以我的示例有一些用于类检查的解决方法。

<script type="text/javascript" class="append-on-ajax-script">
$.post(
    $(this).prop('href'),
    {'some_data':'some_value'},
    function(data) {
        var script = $.parseHTML(data, true);
        for (var i = 0; i < script.length; i++) {
            //console.log(i, (' ' + script[i].className + ' ').indexOf(' append-on-ajax-script ') > -1 );
            if ((' ' + script[i].className + ' ').indexOf(' append-on-ajax-script ') > -1) {
                // console.log(i, script[i]);
                $('body').append(script[i]);
            }
        }

    }
);
</script>

<script type="text/javascript" class="append-on-ajax-script">
    alert('repeat me on ajax');
</script>
于 2018-05-07T18:54:15.527 回答