您怎么可以可靠地和动态加载JavaScript的文件?这将可以用于实现一个模块或组件时'初始化'的组成部分将动态加载的所有需要JavaScript库脚本需求。

客户使用的组件不需要为装载所有的图书馆脚本文件(和手工插入 <script> 标签进入他们的网页),执行这一组成部分-只是'主要'件脚本文件。

如何做主流JavaScript图书馆完成此(原型。等)? 做这些工具合并多个JavaScript文件合并成一个单一的可再发'建立'版本的一个脚本文件?或者他们做的任何动态加载的附属的图书馆'脚本?

除了这个问题: 有没有办法处理该事件之后的动态包括JavaScript文件加载? 原型 document.observe 对于文件范围的活动。例如:

document.observe("dom:loaded", function() {
  // initially hide all containers for tab content
  $$('div.tabcontent').invoke('hide');
});

什么是可利用的事件对于一个脚本元素?

有帮助吗?

解决方案

你可以写的动态脚本标记(使用 原型):

new Element("script", {src: "myBigCodeLibrary.js", type: "text/javascript"});

这里的问题是,我们不知道 外脚本文件是全面装载。

我们常常想要我们的受扶养人的代码,在下一个线和喜欢写东西,如:

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

有一个聪明的方式注入脚本的依赖关系而不需要回调。你只需要拉在通过一个脚本 同阿贾克斯的请求 和eval脚本在全球一级。

如果你使用原型的脚本。负载的方法看起来是这样的:

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);
    }
};

其他提示

没有进口/include/需要在javascript,但主要有两种方式达到什么样的你想要的:

1-你可以载有AJAX呼然后使用eval。

这是最简单的方法,但它仅限于你的领域,因为Javascript安全设置和使用eval是开门虫和黑客.

2添加一个脚本标记的脚本URL在HTML。

肯定是最好的路要走。你可以载脚本,甚至从一个外国服务器,以及它是干净的,因为你使用浏览器分析评估的代码。你可以把标签的头部的网页,或是在底部的机构。

这两个解决方案的讨论和说明在这里。

现在,有一个大问题你必须知道。这样做意味着你远程负荷的代码。现代网络浏览器将装载文件,并继续执行你目前的脚本,因为他们负荷的一切异步改善的表演。

这意味着,如果你使用这些技巧是直接的,你不能用你的新装载码的下行之后,你问它被装载的,因为它将仍装载。

例如:my_lovely_script.js 包含MySuperObject

var js = document.createElement("script");

js.type = "text/javascript";
js.src = jsFilePath;

document.body.appendChild(js);

var s = new MySuperObject();

Error : MySuperObject is undefined

然后你重新载入页面打F5。和它的工作!令人困惑...

所以怎么做呢?

好了,你可以用黑客作者建议在本链接我给你。总之,人们在赶时间,他利用连接的事件,以运行回拨功能脚本时加载。所以你可以把所有的代码使用的远程图书馆在回调功能。例如:

function loadScript(url, callback)
{
    // adding the script tag to the head as suggested before
   var head = document.getElementsByTagName('head')[0];
   var script = document.createElement('script');
   script.type = 'text/javascript';
   script.src = url;

   // then bind the event to the callback function 
   // there are several events for cross browser compatibility
   script.onreadystatechange = callback;
   script.onload = callback;

   // fire the loading
   head.appendChild(script);
}

然后你写的代码你想用脚本后被装载在一氧功能:

var myPrettyCode = function() {
    // here, do what ever you want
};

然后你所有的是:

loadScript("my_lovely_script.js", myPrettyCode);

好吧,我得到了它。但这是一个痛苦编写所有这些东西。

那么,在这种情况下,可以使用始终是梦幻般的免费s架构,这让你做同样的东西在一个线:

$.getScript("my_lovely_script.js", function() {
    alert("Script loaded and executed.");
    // here you can use anything you defined in the loaded script
});

我用一个 更复杂的版本最近jQuery:

<script src="scripts/jquery.js"></script>
<script>
  var js = ["scripts/jquery.dimensions.js", "scripts/shadedborder.js", "scripts/jqmodal.js", "scripts/main.js"];
  var $head = $("head");
  for (var i = 0; i < js.length; i++) {
    $head.append("<script src=\"" + js[i] + "\"></scr" + "ipt>");
  }
</script>

它的工作伟大的在每一个我浏览器进行了测试:IE6/7,火狐,野生动物园,歌剧。

更新: jQuery小的版本:

<script>
  var js = ["scripts/jquery.dimensions.js", "scripts/shadedborder.js", "scripts/jqmodal.js", "scripts/main.js"];
  for (var i = 0, l = js.length; i < l; i++) {
    document.getElementsByTagName("head")[0].innerHTML += ("<script src=\"" + js[i] + "\"></scr" + "ipt>");
  }
</script>

我没有基本上相同的事情,你有没有亚当的,但有轻微修改,以确保我追加到头的标签要做的工作。我只是创造了一个包括功能(代码如下)来处理这两个脚本和css文件。

这一功能还进行检查,以确保脚本或文件尚未载入的动态。它没有检查手工编码的价值观和可能有一个更好的方式来做到这一点,但它服务的目的。

function include( url, type ){
    // First make sure it hasn't been loaded by something else.
    if( Array.contains( includedFile, url ) )
        return;

    // Determine the MIME-type
    var jsExpr = new RegExp( "js$", "i" );
    var cssExpr = new RegExp( "css$", "i" );
    if( type == null )
        if( jsExpr.test( url ) )
            type = 'text/javascript';
        else if( cssExpr.test( url ) )
            type = 'text/css';

    // Create the appropriate element.
    var tag = null;
    switch( type ){
        case 'text/javascript' :
            tag = document.createElement( 'script' );
            tag.type = type;
            tag.src = url;
            break;
        case 'text/css' :
            tag = document.createElement( 'link' );
            tag.rel = 'stylesheet';
            tag.type = type;
            tag.href = url;
            break;
    }

    // Insert it to the <head> and the array to ensure it is not
    // loaded again.
    document.getElementsByTagName("head")[0].appendChild( tag );
    Array.add( includedFile, url );
}

另一个令人敬畏的答案

$.getScript("my_lovely_script.js", function(){


   alert("Script loaded and executed.");
  // here you can use anything you defined in the loaded script

 });

https://stackoverflow.com/a/950146/671046

这里是一些例子码我发现...没有任何人有一个更好的办法?

  function include(url)
  {
    var s = document.createElement("script");
    s.setAttribute("type", "text/javascript");
    s.setAttribute("src", url);
    var nodes = document.getElementsByTagName("*");
    var node = nodes[nodes.length -1].parentNode;
    node.appendChild(s);
  }

如果你有jQuery装了,你应该使用 $.getScript.

这具有一个优势,其他的答案在这里,你有一个建立在回呼功能(保证脚本是装载之前受抚养者的代码运行),你可以控制的缓存。

没有任何人有一个更好的办法?

我认为只是添加脚本身将是更加容易,然后将它添加到最后一个节点网页。这个怎么样:

function include(url) {
  var s = document.createElement("script");
  s.setAttribute("type", "text/javascript");
  s.setAttribute("src", url);
  document.body.appendChild(s);
}

我已经使用的又一个解决方案我在网络上找到...这一个是在creativecommons和它 检查是否源是包括现有电话的功能 ...

你可以找到这里的文件: include.js

/** include - including .js files from JS - bfults@gmail.com - 2005-02-09
 ** Code licensed under Creative Commons Attribution-ShareAlike License 
 ** http://creativecommons.org/licenses/by-sa/2.0/
 **/              
var hIncludes = null;
function include(sURI)
{   
  if (document.getElementsByTagName)
  {   
    if (!hIncludes)
    {
      hIncludes = {}; 
      var cScripts = document.getElementsByTagName("script");
      for (var i=0,len=cScripts.length; i < len; i++)
        if (cScripts[i].src) hIncludes[cScripts[i].src] = true;
    }
    if (!hIncludes[sURI])
    {
      var oNew = document.createElement("script");
      oNew.type = "text/javascript";
      oNew.src = sURI;
      hIncludes[sURI]=true;
      document.getElementsByTagName("head")[0].appendChild(oNew);
    }
  }   
} 

只是发现了一个伟大的功能 衣3 (在撰写本文时,可在预释放)。你可以很容易地插入的依赖性,波图书馆和"外部"的模块(你在找什么)没有太多的代码: 衣装载机.

它还回答了你的第二个问题有关的功能被称为为一旦外部模块的装载。

例如:

YUI({
    modules: {
        'simple': {
            fullpath: "http://example.com/public/js/simple.js"
        },
        'complicated': {
            fullpath: "http://example.com/public/js/complicated.js"
            requires: ['simple']  // <-- dependency to 'simple' module
        }
    },
    timeout: 10000
}).use('complicated', function(Y, result) {
    // called as soon as 'complicated' is loaded
    if (!result.success) {
        // loading failed, or timeout
        handleError(result.msg);
    } else {
        // call a function that needs 'complicated'
        doSomethingComplicated(...);
    }
});

工作完全对我和具有优势的管理依赖关系。参考文件衣 例锐2日历.

如果你想要一个 同步 脚本载,你需要添加脚本文直接向HTML头的标签。添加这将触发一个 异步 负荷。载脚本文从外部文件的同时,利用把.下一个快速的样本(这是使用部分的其他的答案在这个和其他人员员额):

/*sample requires an additional method for array prototype:*/

if (Array.prototype.contains === undefined) {
Array.prototype.contains = function (obj) {
    var i = this.length;
    while (i--) { if (this[i] === obj) return true; }
    return false;
};
};

/*define object that will wrap our logic*/
var ScriptLoader = {
LoadedFiles: [],

LoadFile: function (url) {
    var self = this;
    if (this.LoadedFiles.contains(url)) return;

    var xhr = new XMLHttpRequest();
    xhr.onload = function () {
        if (xhr.readyState === 4) {
            if (xhr.status === 200) {
                self.LoadedFiles.push(url);
                self.AddScript(xhr.responseText);
            } else {
                if (console) console.error(xhr.statusText);
            }
        }
    };
    xhr.open("GET", url, false);/*last parameter defines if call is async or not*/
    xhr.send(null);
},

AddScript: function (code) {
    var oNew = document.createElement("script");
    oNew.type = "text/javascript";
    oNew.textContent = code;
    document.getElementsByTagName("head")[0].appendChild(oNew);
}
};

/*Load script file. ScriptLoader will check if you try to load a file that has already been loaded (this check might be better, but I'm lazy).*/

ScriptLoader.LoadFile("Scripts/jquery-2.0.1.min.js");
ScriptLoader.LoadFile("Scripts/jquery-2.0.1.min.js");
/*this will be executed right after upper lines. It requires jquery to execute. It requires a HTML input with id "tb1"*/
$(function () { alert($('#tb1').val()); });

这种技术,我们在工作中使用的是请求javascript文件使用的AJAX请求,然后eval()返回。如果你使用原型图书馆,他们支持这种功能在他们的Ajax。请求的呼吁。

jquery解决这对我来说与其。append()function -使用这个装载完成捷包

/*
 * FILENAME : project.library.js
 * USAGE    : loads any javascript library
 */
    var dirPath = "../js/";
    var library = ["functions.js","swfobject.js","jquery.jeditable.mini.js","jquery-ui-1.8.8.custom.min.js","ui/jquery.ui.core.min.js","ui/jquery.ui.widget.min.js","ui/jquery.ui.position.min.js","ui/jquery.ui.button.min.js","ui/jquery.ui.mouse.min.js","ui/jquery.ui.dialog.min.js","ui/jquery.effects.core.min.js","ui/jquery.effects.blind.min.js","ui/jquery.effects.fade.min.js","ui/jquery.effects.slide.min.js","ui/jquery.effects.transfer.min.js"];

    for(var script in library){
        $('head').append('<script type="text/javascript" src="' + dirPath + library[script] + '"></script>');
    }

使用 -在你html/php/etc后进口jquery.js 你只包括这一文件所载的全部库追加它的头部...

<script type="text/javascript" src="project.library.js"></script>

保持好,短、简单和易于维护的!:]

// 3rd party plugins / script (don't forget the full path is necessary)
var FULL_PATH = '', s =
[
    FULL_PATH + 'plugins/script.js'      // Script example
    FULL_PATH + 'plugins/jquery.1.2.js', // jQuery Library 
    FULL_PATH + 'plugins/crypto-js/hmac-sha1.js',      // CryptoJS
    FULL_PATH + 'plugins/crypto-js/enc-base64-min.js'  // CryptoJS
];

function load(url)
{
    var ajax = new XMLHttpRequest();
    ajax.open('GET', url, false);
    ajax.onreadystatechange = function ()
    {
        var script = ajax.response || ajax.responseText;
        if (ajax.readyState === 4)
        {
            switch(ajax.status)
            {
                case 200:
                    eval.apply( window, [script] );
                    console.log("library loaded: ", url);
                    break;
                default:
                    console.log("ERROR: library not loaded: ", url);
            }
        }
    };
    ajax.send(null);
}

 // initialize a single load 
load('plugins/script.js');

// initialize a full load of scripts
if (s.length > 0)
{
    for (i = 0; i < s.length; i++)
    {
        load(s[i]);
    }
}

这个代码是一个简单的短功能的示例, 可能 需要额外的功能,功能的完全支持在任何(或给定)的平台。

有一个新提议的通信机制详解的标准称为 动态进口, 最近并入的铬和野生动物园。

const moduleSpecifier = './dir/someModule.js';

import(moduleSpecifier)
   .then(someModule => someModule.foo()); // executes foo method in someModule

有脚本,专门用于这一目的。

yepnope.js 是建立进入接着被和 lab.js 是一个更加优化(但不用户友好的版本。

我不建议这样做,通过一个大图书馆等jquery或原型,因为主要好处之一的一个脚本加载程序的能力负荷脚本早-你不应该等待直到的互动教科书与所有dom元件负荷运行前检查,看看如果你想要动态加载一个脚本。

我写了一个简单的模块,该模块automatizes工作的进口/包括模块中的脚本JavaScript。试一试,并请腾出一些反馈意见。:)详细说明的代码指向这个博客的员额: http://stamat.wordpress.com/2013/04/12/javascript-require-import-include-modules/

var _rmod = _rmod || {}; //require module namespace
_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;
    }
};

//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 np = script_name.split('.');
    if (np[np.length-1] === '*') {
        np.pop();
        np.push('_all');
    }

    script_name = np.join('.');
    var uri = _rmod.libpath + np.join('/')+'.js';
    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);
};

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

require('ivar.util.array');
require('ivar.util.string');
require('ivar.net.*');

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

我失去了所有这些样品,但是今天我需要加载有外部的。js从我的主。js和我这样做:

document.write("<script src='https://www.google.com/recaptcha/api.js'></script>");

在这里, 是一个简单的一个带回调和即支持:

function loadScript(url, callback) {

    var script = document.createElement("script")
    script.type = "text/javascript";

    if (script.readyState) { //IE
        script.onreadystatechange = function () {
            if (script.readyState == "loaded" || script.readyState == "complete") {
                script.onreadystatechange = null;
                callback();
            }
        };
    } else { //Others
        script.onload = function () {
            callback();
        };
    }

    script.src = url;
    document.getElementsByTagName("head")[0].appendChild(script);
}

loadScript("https://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js", function () {

     //jQuery loaded
     console.log('jquery loaded');

});

在这里,一个简单的例子为一个功能负荷JS文件。相关的要点:

  • 你不需要jQuery,所以你可以用这个最初载还的jQuery.js 文件
  • 它是异步带回调
  • 它确保它加载只有一次,因为它保持一个外壳的记录载入网址,从而避免了使用网络
  • 相反jQuery $.ajax$.getScript 你可以用现时,解决这样的问题CSP unsafe-inline.只是使用的财产 script.nonce
var getScriptOnce = function() {

    var scriptArray = []; //array of urls (closure)

    //function to defer loading of script
    return function (url, callback){
        //the array doesn't have such url
        if (scriptArray.indexOf(url) === -1){

            var script=document.createElement('script');
            script.src=url;
            var head=document.getElementsByTagName('head')[0],
                done=false;

            script.onload=script.onreadystatechange = function(){
                if ( !done && (!this.readyState || this.readyState == 'loaded' || this.readyState == 'complete') ) {
                    done=true;
                    if (typeof callback === 'function') {
                        callback();
                    }
                    script.onload = script.onreadystatechange = null;
                    head.removeChild(script);

                    scriptArray.push(url);
                }
            };

            head.appendChild(script);
        }
    };
}();

现在你用简单地通过

getScriptOnce("url_of_your_JS_file.js");

一个荒谬的一个衬垫,用于那些认为装载js库不应该超过一行代码:P

await new Promise((resolve, reject) => {let js = document.createElement("script"); js.src="mylibrary.js"; js.onload=resolve; js.onerror=reject; document.body.appendChild(js)});

显然,如果剧本你要导入一个模块,可以使用 import(...) 功能。

所有主要javascript等库jscript、原型,唯有支持载脚本文件。例如,在锐装载后核心你可以下载的历控制

var loader = new YAHOO.util.YUILoader({

    require: ['calendar'], // what components?

    base: '../../build/',//where do they live?

    //filter: "DEBUG",  //use debug versions (or apply some
                        //some other filter?

    //loadOptional: true, //load all optional dependencies?

    //onSuccess is the function that YUI Loader
    //should call when all components are successfully loaded.
    onSuccess: function() {
        //Once the YUI Calendar Control and dependencies are on
        //the page, we'll verify that our target container is 
        //available in the DOM and then instantiate a default
        //calendar into it:
        YAHOO.util.Event.onAvailable("calendar_container", function() {
            var myCal = new YAHOO.widget.Calendar("mycal_id", "calendar_container");
            myCal.render();
        })
     },

    // should a failure occur, the onFailure function will be executed
    onFailure: function(o) {
        alert("error: " + YAHOO.lang.dump(o));
    }

 });

// Calculate the dependency and insert the required scripts and css resources
// into the document
loader.insert();

我知道我的答案是晚于这个问题,但是,这里是一个伟大文章 www.html5rocks.com - 深入的浑水装脚本 .

在这篇文章得出结论,在有关的浏览器的支持,最好的方式来动态加载JavaScript文件没有阻塞内容呈现以下的方式:

考虑到你已经四个脚本名为 script1.js, script2.js, script3.js, script4.js 然后你可以做到这一点 应用异步=false:

[
  'script1.js',
  'script2.js',
  'script3.js',
  'script4.js'
].forEach(function(src) {
  var script = document.createElement('script');
  script.src = src;
  script.async = false;
  document.head.appendChild(script);
});

现在, 规格说:下载到一起,执行为了尽快所有下载。

Firefox < 3.6、歌剧院说: 我不知道这是什么"异步"的事情,但它只是发生我执行的脚本中加入通过JS在为他们加入。

Safari5.0说: 我明白了"异步",但不明白它以"虚假"与JS。我执行你的脚本,尽快为他们的土地,在任何顺序。

即 < 10中说: 不知道有关"异步",但有一个解决方法使用"onreadystatechange".

一切说: 我是你的朋友,我们将做到这一点的书。

现在,全代码即 < 10解决办法:

var scripts = [
  'script1.js',
  'script2.js',
  'script3.js',
  'script4.js'
];
var src;
var script;
var pendingScripts = [];
var firstScript = document.scripts[0];

// Watch scripts load in IE
function stateChange() {
  // Execute as many scripts in order as we can
  var pendingScript;
  while (pendingScripts[0] && pendingScripts[0].readyState == 'loaded') {
    pendingScript = pendingScripts.shift();
    // avoid future loading events from this script (eg, if src changes)
    pendingScript.onreadystatechange = null;
    // can't just appendChild, old IE bug if element isn't closed
    firstScript.parentNode.insertBefore(pendingScript, firstScript);
  }
}

// loop through our script urls
while (src = scripts.shift()) {
  if ('async' in firstScript) { // modern browsers
    script = document.createElement('script');
    script.async = false;
    script.src = src;
    document.head.appendChild(script);
  }
  else if (firstScript.readyState) { // IE<10
    // create a script and add it to our todo pile
    script = document.createElement('script');
    pendingScripts.push(script);
    // listen for state changes
    script.onreadystatechange = stateChange;
    // must set src AFTER adding onreadystatechange listener
    // else we’ll miss the loaded event for cached scripts
    script.src = src;
  }
  else { // fall back to defer
    document.write('<script src="' + src + '" defer></'+'script>');
  }
}

一些技巧和缩小后,它362字节

!function(e,t,r){function n(){for(;d[0]&&"loaded"==d[0][f];)c=d.shift(),c[o]=!i.parentNode.insertBefore(c,i)}for(var s,a,c,d=[],i=e.scripts[0],o="onreadystatechange",f="readyState";s=r.shift();)a=e.createElement(t),"async"in i?(a.async=!1,e.head.appendChild(a)):i[f]?(d.push(a),a[o]=n):e.write("<"+t+' src="'+s+'" defer></'+t+">"),a.src=s}(document,"script",[
  "//other-domain.com/1.js",
  "2.js"
])

像这样的东西...

<script>
     $(document).ready(function() {
          $('body').append('<script src="https://maps.googleapis.com/maps/api/js?key=KEY&libraries=places&callback=getCurrentPickupLocation" async defer><\/script>');
     });
</script>
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top