【问题标题】:Where are scripts loaded after an ajax call?ajax 调用后脚本在哪里加载?
【发布时间】:2011-11-22 21:43:06
【问题描述】:

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

- 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 属性并将link 项附加到文件。

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

这是一个错误吗? jQuery AJAX 方法的限制? $('script') 不应该反映 所有 已加载的脚本吗?

* 编辑 *

在哭泣和咬牙切齿之后,我决定采用 Kevin B 的解决方案,但是,我无法让它工作,主要是因为 plugin.js 代码在 scriptNode 被插入时运行,但是在插件代码中,该节点尚未插入,因此在 $('script') 数组中不可用 - 所以我仍然是 SOL。我把所有的代码都放在这里了:

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

【问题讨论】:

    标签: javascript jquery jquery-selectors


    【解决方案1】:

    将 HTML 添加到 DOM 的 jQuery 代码总是去掉 &lt;script&gt; 标记。它运行它们,然后将它们扔掉。

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

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

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

    【讨论】:

    • 哦……真恶心。我已经测试了$('#main').load() 方法,它的行为似乎相同。它确实运行脚本,但它也将其丢弃...
    • 当您执行特殊技巧以仅选择 AJAX 调用返回的 HTML 片段时,它会运行脚本。
    • 哦,我明白了……所以听起来 Kevin B 的野兽代码可能是我唯一的选择。呜呜呜……
    • 你对我问凯文 B 的问题有什么想法吗?
    • 这很难做到。我认为这可能需要退后一步并尝试完全提出替代策略。
    【解决方案2】:

    您可以使用 $.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;
    });
    

    【讨论】:

    • 好的,让我重定向问题:如果我想在调用我的脚本标签上获取css 属性,除了我目前正在做的方式之外,我该怎么做是吗?
    • 是的,您提出的解决方案会奏效。问题是我想在调用的脚本中处理这个问题,这样调用者就不需要负责这种特殊处理
    • 这是可以理解的。也许你最好只做我对 $.ajax 所做的事情,而不实际处理任何事情。我会发布一个样本。我从来没有这样用过,但只要你的脚本在他们改变的元素之后,它就可以工作。
    • 我对您的上次编辑感到很兴奋,但它不起作用。实际上,这篇博文:poeticcode.wordpress.com/2007/10/03/innerhtml-and-script-tags/… 在 jQuery 的上下文之外讨论了这个问题,这基本上相当于你的第一个建议。我已经结束了这个问题,因为我认为这是唯一的解决方案。
    • 我重新打开了这个问题,因为我无法让您的解决方案发挥作用。我把所有的代码都放在这里了:arix.com/tmp/loadWithJs,希望你能看看。基本上,plugin.js 中的代码在追加 scriptNode 时运行(我正在追加到头部) - 但是,当时尚未追加节点,因此在 $('script') 数组中尚不可用 -所以我还是 SOL
    【解决方案3】:

    我的解决方案会很简单

    为什么不在 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 的教程。)

    【讨论】:

    • 我认为为什么你不能一遍又一遍地执行 Javascript,没有某种类型的“努力”,是因为它可以很容易地阻止它,让它简单地重做一百万个任务次。 (而且您的服务器不会因此而喜欢您。但只是一个理论。)
    • 嘿丹尼尔,感谢您的加入!预加载文件是不合适的,因为根据用户想要做什么,我们将加载不同的文件。所以加载所有东西都会很昂贵而且不是很有用
    • 不客气。现在已经破解了半个小时,甚至一个小时。该睡觉了。 ^^ 呵呵。 (不时成为程序员的诅咒。)
    • Ups,想发布更多内容。加载 JS 文件,并不重要。这些天最重要的是,如果你真的使用它。 (以 Coffee And Power 为例。我认为我们有大约 50-100 个 JS 文件。)您只需在需要时“激活/参与”实际代码。 (我们真正使用 AJAX 的唯一目的就是向 PHP 发送数据。粗略地说。)
    【解决方案4】:

    这里的一个问题是您不能在每个页面中重新加载 jQuery。只是主页 应该有 jQuery 调用:

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

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

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

    【讨论】:

    • 我将它加载到 child 页面中只是因为人们可以直接调用它并看到中间没有 jQuery .load() 一切都可以正常工作。但这不是必需的,我已经从我在 arix.com 的版本中删除了它 - 没有解决问题
    【解决方案5】:

    好的,经过多次努力,我已将 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'); }
        });
    });
    

    【讨论】:

    猜你喜欢
    • 2017-11-17
    • 1970-01-01
    • 1970-01-01
    • 2014-03-02
    • 1970-01-01
    • 2022-01-13
    • 1970-01-01
    • 2016-05-22
    • 1970-01-01
    相关资源
    最近更新 更多