在ajax调用之后加载脚本的位置在哪里?

时间:2011-11-22 21:43:07

标签: javascript jquery jquery-selectors

假设您有一个简单的网页,可以动态加载如下所示的内容:

- main.html -

<!DOCTYPE html>
<html xmlns="https://www.w3.org/1999/xhtml">
<head>
<script type="text/javascript"
   src="https://ajax.aspnetcdn.com/ajax/jquery/jquery-1.6.2.js">
</script>
<script type="text/javascript">
$(function() {
    $.ajax({
         type: 'get', cache: false, url: '/svc.html',
         success: function(h) {
             $('#main').html(h);
         }
    });
});
</script>
</head>

<body>
    <div id='main'>
    loading...
    </div>
</body>
</html>

并且它加载的页面在单独的文件中使用了一点Javascript:

- svc.html -

<script type="text/javascript"
   src="https://ajax.aspnetcdn.com/ajax/jquery/jquery-1.6.2.js">
</script>
<script type="text/javascript" src="/plugin.js" css="/plugin.css"></script>
<div id='inner'>
dynamically loaded content
</div>

注意脚本标记上的css属性 - 它表示属于脚本的样式表以及脚本将为我们加载的样式表。这是脚本:

- plugin.js -

var css = $('<link />', {
    rel: "stylesheet", type: "text/css", href: $('script:last').attr('css')
});
$('head').append(css);

,最后,样式表只是为加载的inner div着色,证明它一切正常:

- plugin.css -

#inner
{
    border: solid 1px blue;
}

现在,您会注意到样式表的加载方式:我们查看$('script')并选择最后一个,然后我们获取css属性并附加{{1} } item到文档的头部。

我可以访问link并运行javascript,加载我的样式表,一切都很酷 - 但是,如果我访问/svc.html,javascript会运行但无法找到{{1}的加载在/main.html的数组中(因此无法加载样式表)。请注意,插件脚本确实运行,它只是看不到自己。

这是一个错误吗? jQuery AJAX方法的局限性?不应该plugin.js反映已加载的所有脚本吗?

*编辑*

经过多次哀号和咬牙切齿之后,我决定选择Kevin B的解决方案,但是,我无法让它工作,主要是因为$('script')代码在$('script')时运行插入,但在插件代码中,节点尚未插入,因此在plugin.js数组中不可用 - 所以我仍然是SOL。我已将所有代码放在此处进行审核:

http://www.arix.com/tmp/loadWithJs/

5 个答案:

答案 0 :(得分:5)

向DOM添加HTML的jQuery代码总是删除<script>标记。它运行它们然后将它们扔掉。

该行为的一个例外是当你使用“$ .load()”和hack时,你可以加载一个页面片段:

$.load("http://something.com/whatever #stuff_I_want", function() { ... });

在这种情况下,脚本将被剥离并且评估/运行。

答案 1 :(得分:1)

你可以使用$ .ajax来获取html,自己去掉脚本标签,附加内容,然后将脚本标签附加到你想要它的dom中的位置,以便它以你想要的方式执行到。

$.ajax({...}).done(function(html){
  var htmlToAppend = html;

  // replace all script tags with divs
  htmlToAppend.replace(/<script/ig,"<div class='script'");
  htmlToAppend.replace(/<\/script>/ig,"</div>");

  // detach script divs from html
  htmlToAppend = $(htmlToAppend);
  var scripts = htmlToAppend.find(".script").detach();

  // append html to target div
  htmlToAppend.appendTo("#target");

  // loop through scripts and append them to the dom
  scripts.each(function(){
    var $script = $(this), 
        scriptText = $script.html(), 
        scriptNode = document.createElement('script');

    $(scriptNode).attr('css', $script.attr('css');
    scriptNode.appendChild(document.createTextNode(scriptText));
    $("#target")[0].appendChild(scriptNode);
  });

});

我没有测试过这段代码,但它是基于history.js的代码

编辑:这是一个更适合您需求的简单解决方案:

$("#target").load(url,function(obj){
    // get css attribute from script tag using the raw returned html
    var cssPath = obj.responseText.match(/css="(.*)"/i)[1];
    $('<link />', {
        rel: "stylesheet", type: "text/css", href: cssPath
    }).appendTo('head');

});

因为.load()剥离脚本标记然后执行它们,这将读取原始响应文本并从中获取css路径,然后添加链接元素。

我不完全确定为什么会这样处理。

编辑:见评论。

$.ajax({...}).done(function(html){
  $("#target")[0].innerHTML = html;
});

答案 2 :(得分:1)

我的解决方案很简单

为什么不在第一次加载时加载main中所需的文件?然后简单地有一个监听器事件。 (检查内容是否只是加载?)

按需加载的唯一解决方案......

你只需要AJAX调用脚本文件本身......

<script type="text/javascript">
$(function () {
    $.ajax({
        type: 'get',
        cache: false, 
        url: 'svc.html',
            success: function(response) {
                if (response) { // If any response aka, loaded the svc.html file...
                    $('#main').html(response);
                    $.ajax({
                        url: 'plugin.js',
                        dataType: 'script',
                        success: function(reponse) {
                            // You can now do something with the response here even...
                        }
                    });
                }
            }
    });
});
</script>

我的方式

在显示任何内容之前,在加载的实际页面上制作某种类型的加载程序。 (很多关于网络的jQuery教程。)

答案 3 :(得分:0)

这里的问题是你无法在每个页面重新加载jQuery。只是主页  应该有jQuery调用:

<script type='text/javascript' src='jQuery-url'></script>

或者只有一个页面可以调用它,只有孩子(是的,页面。从那里加载)将能够使用jQuery。

在我吸取教训之前,我曾经遇到过几次。这可能不是您问题的完整答案,但可能是解决问题的开始。

答案 4 :(得分:0)

好吧,经过多次努力,我已经将Kevin B的解决方案应用到了对其他人有用的插件中。欢迎改进! (我应该把它放在github吗?)

- loadWithJs.js -

// inspired by Kevin B's suggestions
// at: http://stackoverflow.com/questions/8234215/where-are-scripts-loaded-after-an-ajax-call

(function ($) {
    $.fn.loadWithJs = function (o) {
        var target = this;
        var success = o.success;

        o.success = function (html) {
            // convert script tags
            html = $('<div />').append(
                html.replace(/<(\/)?script/ig, "<$1codex")
            );
            // detach script divs from html
            var scripts = html.find("codex").detach();
            // populate target
            target.html(html.children());

            // loop through scripts and append them to the dom
            scripts.each(function () {
                var script = $(this)[0];
                var scriptNode = document.createElement('script');

                for (var i = 0; i < script.attributes.length; i++) {
                    var attr = script.attributes[i];
                    $(scriptNode).attr(attr.name, attr.value);
                }
                scriptNode.appendChild(
                    document.createTextNode($(script).html())
                );
                target[0].appendChild(scriptNode);
            });

            if (success) success();
        };

        $.ajax(o);
    };
})(jQuery);
然后调用者可以这样做:

$(function() {
    $('#main').loadWithJs({
         type: 'get', cache: false, 
         url: '/svc.html',
         success: function() { console.log('loaded'); }
    });
});