使用javascript根据需要注入脚本引用?

时间:2008-10-14 22:36:12

标签: javascript include

我有一个可能偶尔会在某些页面上使用的JS函数。它依赖于另一个JS文件(swfObject.js),但我希望避免在整个地方都包含这个文件,因为大多数情况下都是浪费请求。

相反,我想创建一个可以根据需要将脚本引用注入页面DOM的泛型函数,因此如果调用此函数,它将检查脚本,如果它不存在,则加载它英寸

我很确定这是可能的(我不打算使用document.write),但在我冒险进入未知领域之前,有没有人之前做过这个,如果有的话,还有什么指针?

编辑:好的,我试过了,它适用于IE6和FF,我还没有测试过其他浏览器。

这是我的代码(Rev 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();

有什么建议吗?

6 个答案:

答案 0 :(得分:4)

如果您使用的是更高级别的框架,例如JQuery,则可以查看$.getScript(url, callback)函数。

答案 1 :(得分:3)

如果你想让你的代码在下一行,并喜欢写下这样的代码:

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

有一种智能方法可以在不需要回调的情况下注入脚本依赖 。您只需通过同步AJAX请求来提取脚本,并在全局级别上评估脚本。

如果使用Prototype,则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);
  }
};

答案 2 :(得分:0)

签出YUI Loader工具。它是用于按需加载脚本的超级方便,不显眼的javascript。

以下是使用非YUI脚本的示例的链接:

http://developer.yahoo.com/yui/examples/yuiloader/yl-addmodule.html

答案 3 :(得分:0)

如果脚本本身中包含document.write,这些方法(包括document.writing脚本标记)都不起作用。

答案 4 :(得分: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);
};

答案 5 :(得分:0)

考虑使用require.js。这可能需要对您的前端框架进行一些修改,但这完全是值得的。使用require,您可以在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
});
相关问题