2008-10-14 53 views
12

我有一个JS函数可能偶尔会在某些页面上使用。它依赖于另一个JS文件(swfObject.js),但是我想避免将该文件包含在整个地方,因为这是大多数时候浪费的请求。使用JavaScript来根据需要注入脚本引用?

相反,我想创建一个通用的功能,根据需要,可以注入脚本引用到页面的DOM,所以如果这个函数被调用,它会检查脚本,如果它不存在,负载它在。

我很确定这是可能的(我不打算使用document.write),但在我冒险进入未知领域之前,有人曾经这样做过,如果是这样,任何指针?

编辑:好吧,我试了一下,它在IE6和FF的工作,我还没有测试其他浏览器。

这里是我的代码(版本2.0,现在可选的回调):

function loadJSInclude(scriptPath, callback) 
{ 
    var scriptNode = document.createElement('SCRIPT'); 
    scriptNode.type = 'text/javascript'; 
    scriptNode.src = scriptPath; 

    var headNode = document.getElementsByTagName('HEAD'); 
    if (headNode[0] != null) 
     headNode[0].appendChild(scriptNode); 

    if (callback != null)  
    { 
     scriptNode.onreadystagechange = callback;    
     scriptNode.onload = callback; 
    } 
} 

,并与依赖的方法:

var callbackMethod = function() 
{ 
    // Code to do after loading swfObject 
} 

// Include SWFObject if its needed 
if (typeof(SWFObject) == 'undefined')  
    loadJSInclude('/js/swfObject.js', callbackMethod); 
else 
    calbackMethod(); 

有什么建议?

+0

我不明白为什么这是必要的 - 一旦被要求在自己的网站/应用程序的任何页面时,它是最有可能无论如何缓存,所以它确实不会伤害任何东西。看起来像很多额外的努力,作为回报这么小。 – 2008-10-14 22:47:03

+0

Jason,我们有数百个文件可能会使用这段代码,所以我宁愿有能力在客户端执行此操作(通过我们的CMS系统),而不必重新编译站点以在脚本中添加脚本引用.CS文件。 – FlySwat 2008-10-14 22:48:32

回答

4

如果您使用的是更高层次的框架如jQuery,你可以检查出$.getScript(url, callback)功能。

3

如果你想你就非常下一行代码,并喜欢写的东西,如:

if (iNeedSomeMore){ 
    Script.load("myBigCodeLibrary.js"); // includes code for myFancyMethod(); 
    myFancyMethod();      // cool, no need for callbacks! 
} 

有注入脚本相关而不需要回调的一个聪明的办法。您只需通过同步AJAX请求来拉动脚本,并在全局级别上评估该脚本。

如果使用原型的Script.load方法是这样的:

var Script = { 
    _loadedScripts: [], 
    include: function(script){ 
    // include script only once 
    if (this._loadedScripts.include(script)){ 
     return false; 
    } 
    // request file synchronous 
    var code = new Ajax.Request(script, { 
     asynchronous: false, method: "GET", 
     evalJS: false, evalJSON: false 
    }).transport.responseText; 
    // eval code on global level 
    if (Prototype.Browser.IE) { 
     window.execScript(code); 
    } else if (Prototype.Browser.WebKit){ 
     $$("head").first().insert(Object.extend(
     new Element("script", {type: "text/javascript"}), {text: code} 
    )); 
    } else { 
     window.eval(code); 
    } 
    // remember included script 
    this._loadedScripts.push(script); 
    } 
}; 
0

的这些方法,包括document.writing脚本标签无,工作,如果脚本本身中有一个文件撰写。

0

我写了一个简单的模块,它可以自动化导入/包括JavaScript中的模块脚本。试试吧,请留下一些反馈! :)对于代码的详细说明,请参阅这篇博客文章:http://stamat.wordpress.com/2013/04/12/javascript-require-import-include-modules/

// ----- USAGE ----- 

require('ivar.util.string'); 
require('ivar.net.*'); 
require('ivar/util/array.js'); 
require('http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js'); 

ready(function(){ 
    //do something when required scripts are loaded 
}); 

    //-------------------- 

var _rmod = _rmod || {}; //require module namespace 
_rmod.LOADED = false; 
_rmod.on_ready_fn_stack = []; 
_rmod.libpath = ''; 
_rmod.imported = {}; 
_rmod.loading = { 
    scripts: {}, 
    length: 0 
}; 

_rmod.findScriptPath = function(script_name) { 
    var script_elems = document.getElementsByTagName('script'); 
    for (var i = 0; i < script_elems.length; i++) { 
     if (script_elems[i].src.endsWith(script_name)) { 
      var href = window.location.href; 
      href = href.substring(0, href.lastIndexOf('/')); 
      var url = script_elems[i].src.substring(0, script_elems[i].length - script_name.length); 
      return url.substring(href.length+1, url.length); 
     } 
    } 
    return ''; 
}; 

_rmod.libpath = _rmod.findScriptPath('script.js'); //Path of your main script used to mark the root directory of your library, any library 


_rmod.injectScript = function(script_name, uri, callback, prepare) { 

    if(!prepare) 
     prepare(script_name, uri); 

    var script_elem = document.createElement('script'); 
    script_elem.type = 'text/javascript'; 
    script_elem.title = script_name; 
    script_elem.src = uri; 
    script_elem.async = true; 
    script_elem.defer = false; 

    if(!callback) 
     script_elem.onload = function() { 
      callback(script_name, uri); 
     }; 

    document.getElementsByTagName('head')[0].appendChild(script_elem); 
}; 

_rmod.requirePrepare = function(script_name, uri) { 
    _rmod.loading.scripts[script_name] = uri; 
    _rmod.loading.length++; 
}; 

_rmod.requireCallback = function(script_name, uri) { 
    _rmod.loading.length--; 
    delete _rmod.loading.scripts[script_name]; 
    _rmod.imported[script_name] = uri; 

    if(_rmod.loading.length == 0) 
     _rmod.onReady(); 
}; 

_rmod.onReady = function() { 
    if (!_rmod.LOADED) { 
     for (var i = 0; i < _rmod.on_ready_fn_stack.length; i++){ 
      _rmod.on_ready_fn_stack[i](); 
     }); 
     _rmod.LOADED = true; 
    } 
}; 

_.rmod = namespaceToUri = function(script_name, url) { 
    var np = script_name.split('.'); 
    if (np.getLast() === '*') { 
     np.pop(); 
     np.push('_all'); 
    } 

    if(!url) 
     url = ''; 

    script_name = np.join('.'); 
    return url + np.join('/')+'.js'; 
}; 

//you can rename based on your liking. I chose require, but it can be called include or anything else that is easy for you to remember or write, except import because it is reserved for future use. 
var require = function(script_name) { 
    var uri = ''; 
    if (script_name.indexOf('/') > -1) { 
     uri = script_name; 
     var lastSlash = uri.lastIndexOf('/'); 
     script_name = uri.substring(lastSlash+1, uri.length); 
    } else { 
     uri = _rmod.namespaceToUri(script_name, ivar._private.libpath); 
    } 

    if (!_rmod.loading.scripts.hasOwnProperty(script_name) 
    && !_rmod.imported.hasOwnProperty(script_name)) { 
     _rmod.injectScript(script_name, uri, 
      _rmod.requireCallback, 
       _rmod.requirePrepare); 
    } 
}; 

var ready = function(fn) { 
    _rmod.on_ready_fn_stack.push(fn); 
}; 
0

考虑使用require.js。这可能需要对前端框架进行一些修改,但这完全值得。与需要,你可以只是做你fileUsedOccasionally.js如下:

 
define(['swfObject', 'someOtherDependency'], function (swfObject, someOtherDependency) { 
    // you can now use swfObject as a JS object! you can call it whatever you want 
    // you'll have to write a swfObject.js to wrap it with require 
    // but that's trivial 
});