185

JavaScript ファイルを確実かつ動的に読み込むにはどうすればよいでしょうか? これを使用して、コンポーネントが「初期化」されると、必要なすべての JavaScript ライブラリ スクリプトをオンデマンドで動的にロードするモジュールまたはコンポーネントを実装できます。

コンポーネントを使用するクライアントは、このコンポーネントを実装するすべてのライブラリ スクリプト ファイルをロードする (および Web ページに手動で<script>タグを挿入する) 必要はありません。「メイン」コンポーネント スクリプト ファイルだけです。

主流の JavaScript ライブラリはどのようにこれを実現していますか (プロトタイプ、jQuery など)? これらのツールは、複数の JavaScript ファイルをスクリプト ファイルの単一の再配布可能な「ビルド」バージョンにマージしますか? それとも、補助的な「ライブラリ」スクリプトを動的にロードしますか?

この質問への追加:動的に含まれる JavaScript ファイルが読み込まれた後にイベントを処理する方法はありますか? プロトタイプにはdocument.observe、ドキュメント全体のイベントがあります。例:

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

スクリプト要素で使用できるイベントは何ですか?

4

29 に答える 29

88

Prototypesを使用して、スクリプト要素を動的に作成できます。

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!
}

コールバックを必要とせずにスクリプトの依存関係を注入するスマートな方法があります。同期 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);
    }
};
于 2008-10-28T09:02:37.437 に答える
85

javascript には import / include / require はありませんが、目的を達成するには主に 2 つの方法があります。

1 - AJAX 呼び出しでロードしてから、eval を使用できます。

これは最も簡単な方法ですが、Javascript の安全性設定のためにドメインに制限されており、eval を使用するとバグやハッキングへの扉が開かれます。

2 - HTML にスクリプト URL を含むスクリプト要素を追加します。

間違いなく最善の方法です。外部サーバーからでもスクリプトを読み込むことができ、ブラウザのパーサーを使用してコードを評価するため、クリーンです。要素は、Web ページのscript要素内head、または の下部に配置できますbody

ここでは、これら両方のソリューションについて説明し、図解します。

さて、知っておかなければならない大きな問題があります。これを行うことは、コードをリモートでロードすることを意味します。最新の Web ブラウザーは、パフォーマンスを向上させるためにすべてを非同期に読み込むため、ファイルを読み込み、現在のスクリプトを実行し続けます。

つまり、これらのトリックを直接使用すると、新しくロードされたコードをロードするように要求した後の次の行では、コードがまだロードされているため、使用できなくなります。

EG : 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 キーを押してページをリロードします。そしてそれはうまくいきます!紛らわしい...

それで、それについて何をしますか?

さて、私が提供したリンクで著者が提案するハックを使用できます。要約すると、急いでいる人のために、en イベントを使用して、スクリプトがロードされたときにコールバック関数を実行します。したがって、リモート ライブラリを使用するすべてのコードをコールバック関数に入れることができます。例:

function loadScript(url, callback)
{
    // adding the script element 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);

はい、分かりました。でも、これだけ書くのはめんどくさい。

その場合は、いつものように素晴らしい無料の jQuery フレームワークを使用して、まったく同じことを 1 行で行うことができます。

$.getScript("my_lovely_script.js", function() {
    alert("Script loaded and executed.");
    // here you can use anything you defined in the loaded script
});
于 2013-02-09T09:37:51.497 に答える
31

私は最近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、Firefox、Safari、Operaなど、テストしたすべてのブラウザでうまく機能しました。

更新: 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>
于 2008-08-23T15:52:48.607 に答える
20

私は基本的に Adam と同じことをしましたheadが、作業を完了するために要素に追加していることを確認するために少し変更を加えました。includeスクリプトと CSS ファイルの両方を処理する関数 (以下のコード) を作成しただけです。

この関数は、スクリプトまたは 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 element = null;
    switch( type ){
        case 'text/javascript' :
            element = document.createElement( 'script' );
            element.type = type;
            element.src = url;
            break;
        case 'text/css' :
            element = document.createElement( 'link' );
            element.rel = 'stylesheet';
            element.type = type;
            element.href = url;
            break;
    }
    
    // Insert it to the <head> and the array to ensure it is not
    // loaded again.
    document.getElementsByTagName("head")[0].appendChild( element );
    Array.add( includedFile, url );
}
于 2008-08-21T22:06:42.967 に答える
14

別の素晴らしい答え

$.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

于 2012-04-04T15:07:01.203 に答える
9

ここに私が見つけたいくつかのサンプルコードがあります...誰かがより良い方法を持っていますか?

  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);
  }
于 2008-08-21T22:00:13.887 に答える
6

jQuery が既に読み込まれている場合は、$.getScriptを使用する必要があります。

これには、コールバック関数が組み込まれており(依存コードが実行される前にスクリプトがロードされることを保証するため)、キャッシュを制御できるという点で、ここでの他の回答よりも利点があります。

于 2012-02-13T20:20:32.610 に答える
3

誰かがより良い方法を持っていますか?

スクリプトを本文に追加するだけで、ページの最後のノードに追加するよりも簡単だと思います。これはどう:

function include(url) {
  var s = document.createElement("script");
  s.setAttribute("type", "text/javascript");
  s.setAttribute("src", url);
  document.body.appendChild(s);
}
于 2008-08-21T22:10:08.760 に答える
3

ネットで見つけたさらに別の解決策を使用しました...これは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);
    }
  }   
} 
于 2008-08-26T14:50:30.803 に答える
3

YUI 3の優れた機能について知りました(執筆時点ではプレビュー リリースで利用可能です)。YUI ライブラリーと「外部」モジュール (探しているもの) への依存関係を、あまり多くのコードなしで簡単に挿入できます: YUI Loader

また、外部モジュールがロードされるとすぐに呼び出される関数に関する2番目の質問にも答えます。

例:

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

私にとっては完璧に機能し、依存関係を管理できるという利点があります。YUI 2 calendarの例については、YUI のドキュメントを参照してください。

于 2009-03-26T00:14:38.177 に答える
2

私たちが仕事で使用している手法は、AJAXリクエストを使用してjavascriptファイルをリクエストしてから、eval()を返すことです。プロトタイプライブラリを使用している場合は、Ajax.Request呼び出しでこの機能をサポートしています。

于 2008-08-21T23:03:53.093 に答える
2

jquery は .append() 関数でこれを解決しました - これを使用して完全な jquery ui パッケージをロードしました

/*
 * 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>');
    }

使用するには - jquery.js をインポートした後、html/php/etc のヘッドにこの 1 つのファイルを含めるだけで、ライブラリ全体をロードしてヘッドに追加します...

<script type="text/javascript" src="project.library.js"></script>
于 2011-01-14T09:20:46.797 に答える
1

この目的のために特別に設計されたスクリプトがあります。

yepnope.jsは Modernizr に組み込まれており、lab.jsはより最適化されています (ただし、ユーザー フレンドリーではないバージョンです。

jquery やプロトタイプなどの大きなライブラリを使用してこれを行うことはお勧めしません。スクリプト ローダーの主な利点の 1 つは、スクリプトを早期にロードできることです。jquery とすべての dom 要素がロードされるまで待つ必要はありません。チェックを実行して、スクリプトを動的にロードするかどうかを確認します。

于 2012-02-13T22:01:51.407 に答える
1

JQuery アプローチがいかに便利であるかが気に入っている限り、JavaScript アプローチはそれほど複雑ではありませんが、既に使用しているものを少し調整するだけで済みます... JS を動的にロードする方法 (必要な場合のみ) を次に示します。それらに依存するスクリプトを実行する前にそれらをロードします。

JavaScript アプローチ

//Create a script element that will load
let dynamicScript = document.createElement('script');

//Set source to the script we need to load
dynamicScript.src = 'linkToNeededJsFile.js';

//Set onload to callback function that depends on this script or do inline as shown below
dynamicScript.onload = () => {

    //Code that depends on the loaded script should be here

};

//append the created script element to body element
document.body.append(dynamicScript);

JS でこれを達成する方法は他にもありますが、すべての開発者が関連付けることができる基本的な JS の知識が必要なため、私はこれを好みます。

答えの一部ではありませんが、すでに JQuery を含むプロジェクトで私が好む JQuery バージョンは次のとおりです。

$.getScript('linkToNeededJsFile.js', () => {

    //Code that depends on the loaded script should be here

});

JQueryオプションの詳細はこちら

于 2021-05-22T05:55:54.723 に答える
1

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
});
于 2013-04-12T16:55:25.393 に答える
0

jscript、prototype、YUI などの主要な JavaScript ライブラリはすべて、スクリプト ファイルの読み込みをサポートしています。たとえば、YUI では、コアをロードした後、次のようにしてカレンダー コントロールをロードできます。

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();
于 2008-08-21T22:01:29.437 に答える