仅动态包含javascript文件一次

我有一个我写的javascript函数,它被用来包含一个外部JS文件,但只有一次。 我需要这样一个函数的原因是因为当通过AJAX加载某些内容时我被调用,并且我需要为该内容运行特定于页面的代码(不,只是使用.live不会覆盖它)。

这是我的尝试,为简洁而缩短:

 $.include_once = function(filename) { if ($("script[src='" + filename + "']").length === 0) { var $node = $("") .attr({ src : filename, type : "text/javascript" }) ; $(document.body).append($node); } }; 

这很好用:调用函数,加载外部文件,加载时运行该文件。 完善。

问题是它总是会重新加载那个外部文件:我用来检查脚本是否存在的查询总是找不到任何东西!

在调试时,我添加了一些行:

 alert($("script").length); // alerts: 4 $(document.body).append($node); alert($("script").length); // alerts: 4 

查看动态源代码(Firebug的HTML选项卡),我根本找不到脚本标记。

我知道我可以维护一个我以前包含的文件数组,但是我希望使用这样的方法,如果它工作的话,它看起来更健壮,因为并非所有的JS文件都是以这种方式包括在内。

任何人都可以解释在第二个片段中看到的行为吗?

在这种情况下,jQuery有点愚蠢; 它完全不符合你的期望。 当你append($node) jQuery做到这一点:

 jQuery.ajax({ url: $node.src, async: false, dataType: "script" }) 

Woops! 对于本地文件(例如,在同一个域上),jQuery为.js文件正文执行标准的XMLHttpRequest ,并通过创建标记的整个复杂过程(再次!)继续“eval”它,并将其内容设置为你的.js文件正文。 这是为了模拟eval但是在全局范围内。

对于跨域文件,由于同一域策略无法执行标准XMLHttpRequest ,因此jQuery再次创建元素并将其插入

在上面的本地和跨域案例中,jQuery 终于可以做到这一点:

 head.removeChild(script); 

并开始你的.length检查! 游民。

所以关于你的问题,不要打扰jQuery。 做就是了

 document.getElementsByTagName('head')[0] .appendChild( document.createElement('script') ) .src = filename; 

哪个会做你期望的,特别是稍后查询它。

您正在尝试解决已经多次解决的问题。 试试LazyLoad 。 jQuery也有类似的插件。

不要设置script-tag的source属性,而是设置script标签的“text”属性。 这适用于所有现代浏览器(我在实践中使用的应用程序不支持IE6,因此我不知道这种蠕变…)。

在实践中它看起来像这样(你必须添加代码以省略自己的双重包含 – 例如所有alread加载脚本的简单数组,虽然这是非常特定于应用程序的,为什么你应该加载代码两次?尝试省略双 – 加载代码……!):

 var script_source_code_string = ; var $n = $(""); $n.get(0).text = script_source_code_string; $(document.body).append($n); 

或者甚至更简单(没有jquery,我的代码在这个阶段不知道jquery,它也可能是动态加载的):

 var script_source_code_string = ; var s = document.createElement('script'); document.getElementsByTagName('head')[0].appendChild(s); s.text = script_source_code_string;