どのようにしたら、JavaScriptファイルを確実かつ動的にロードできるのでしょうか? これは、モジュールやコンポーネントを実装する際に、 'initialized' コンポーネントが必要なすべてのJavaScriptライブラリスクリプトをオンデマンドで動的にロードするために使用することができます。
コンポーネントを使用するクライアントは、このコンポーネントを実装するすべてのライブラリスクリプトファイルを読み込む必要はありません (そして、手動で <script>
タグをウェブページに挿入します) - 'main'component script file だけです。
**主流のJavaScriptライブラリ(Prototype、jQueryなど)はどのようにこれを実現しているのでしょうか? あるいは、補助的な 'ライブラリ'スクリプトの動的なロードを行うのでしょうか?
この質問に対する補足です。 動的にインクルードされたJavaScriptファイルがロードされた後のイベントを処理する方法はありますか? Prototypeには、ドキュメント全体のイベントのための document.observe
があります。例
document.observe("dom:loaded", function() {
// initially hide all containers for tab content
$$('div.tabcontent').invoke('hide');
});
**script要素で利用可能なイベントは何ですか?
動的スクリプトタグを書き込むことができます(Prototypeを使用):
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リクエストを介してスクリプトをプルし、グローバルレベルでスクリプトを評価するだけです。
プロトタイプを使用する場合、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);
}
};
JavaScriptにはインポート/インクルード/ニーズはありませんが、必要なものを達成するには主に2つの方法があります。
1-AJAX呼び出しでロードして、evalを使用できます。
これは最も簡単な方法ですが、Javascriptの安全設定によりドメインに限定され、evalを使用するとバグやハッキングの扉が開かれます。
2-HTMLにスクリプトURLを含むスクリプトタグを追加します。
間違いなく最善の方法です。 外部サーバーからでもスクリプトをロードでき、ブラウザパーサーを使用してコードを評価すると、スクリプトはクリーンになります。 < script />を置くことができます。 Webページの先頭または本文の下部にタグを付けます。
これらのソリューションの両方について、ここで説明および説明します。
今、あなたが知らなければならない大きな問題があります。 これを行うと、コードをリモートでロードできます。 最新のWebブラウザーは、パフォーマンスを向上させるためにすべてを非同期でロードするため、ファイルをロードして現在のスクリプトを実行し続けます。
つまり、これらのトリックを直接使用すると、ロードを要求した後、次の行で新しくロードされたコードを使用できなくなります。これは、まだロードされるためです。
E.G: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イベントを使用します。 したがって、リモートライブラリを使用してすべてのコードをコールバック関数に配置できます。 E.G:
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);
わかりました。 しかし、これらすべてを書くのは苦痛です。
まあ、その場合、いつものように素晴らしい無料のjQueryフレームワークを使用できます。これにより、まったく同じことが1行で実行できます。
$.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、Firefox、Safari、Operaでテストしたすべてのブラウザでうまく機能しました。
更新: jQuery-lessバージョン:
<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>
私は基本的にアダムさんと同じことをしましたが、headタグに追加することで仕事ができることを確認するために少し修正しました。 スクリプトとCSSの両方のファイルを処理するために、単純にinclude関数(以下のコード)を作りました。
この関数は、スクリプトや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
});
以下は私が見つけたコードの例ですが、どなたかもっと良い方法をご存知ですか?
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);
}
YUI 3の素晴らしい機能について知りました(執筆時点ではプレビューリリースで入手できます)。 依存関係をYUIライブラリと「外部」モジュール(探しているもの)に簡単に挿入できます。コードが多すぎません:YUIローダー。
また、外部モジュールがロードされるとすぐに呼び出される関数に関する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カレンダーの例については、YUIドキュメントを参照してください。
ネットで見つけたさらに別のソリューションを使用しました。 ... これはクリエイティブコモンズの下にあり、関数を呼び出す前にソースが含まれていたかどうかをチェックします**。 ...
ファイルはここにあります:include.js。
/** include - including .js files from JS - [email protected] - 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);
}
}
}
誰もがより良い方法を持っていますか??
スクリプトを本文に追加するだけの方が、ページの最後のノードに追加する方が簡単だと思います。 これはどうですか:
function include(url) {
var s = document.createElement("script");
s.setAttribute("type", "text/javascript");
s.setAttribute("src", url);
document.body.appendChild(s);
}
SYNC スクリプトの読み込みが必要な場合は、スクリプトテキストをHTML HEADタグに直接追加する必要があります。 < script src = "myscript.js">として追加すると、 ASYNC の負荷がトリガーされます。 外部ファイルからスクリプトテキストを同期してロードするには、XHRを使用します。クイックサンプルの下(この投稿と他の投稿の他の回答の一部を使用しています):
/*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()); });
素晴らしく、短く、シンプルで、メンテナンス可能です。! :]。
// 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]);
}
}
このコードは、任意の(または指定された)プラットフォームで完全にサポートするために追加の機能機能が必要になる可能性がある短い機能例です。
jqueryは.append()関数でこれを解決しました。 -これを使用して、完全なjquery uiパッケージをロードしました。
/ *。
*ファイル名:project.library.js。
* USAGE:JavaScriptライブラリをロードします。
* /。
var dirPath = "。./ js / ";。
varlibrary = ["functions.js"、 "swfobject.js"、 "jquery.jeditable.mini.js"、 "jquery-ui-1.8.8.custom.min.js"、 "ui / jquery.ui.wi.quui.jui.jui
for(ライブラリ内のvarスクリプト){。
$( '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>
ここは、コールバックとIEサポートを備えたシンプルなものです。
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');
});
私の答えはこの質問に少し遅れていることは知っていますが、 www.html5rocks.com -スクリプトの読み込みの暗い水に深く飛び込むの素晴らしい記事があります。 .
その記事では、ブラウザのサポートに関して、コンテンツのレンダリングをブロックせずにJavaScriptファイルを動的にロードする最良の方法は次の方法であると結論付けられています。
script1.js、script2.js、script3.js、script4.js
という名前の4つのスクリプトがあることを考えると、 async = 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);
});
さて、 Specさんのコメント:一緒にダウンロードして、すべてのダウンロードが完了したらすぐに順番に実行してください。
Firefox< 3.6、Operaさんのコメント:この「同期」が何であるかはわかりませんが、JS経由で追加されたスクリプトを、追加された順序で実行するだけです。
Safari 5.0のコメント:「async」は理解していますが、JSで「false」に設定することを理解していません。スクリプトが着陸したらすぐに、任意の順序で実行します。
IE< 10は言う:「async」については何もわかりませんが、「onreadystatechange」を使用した回避策があります。
他のすべては言う:私はあなたの友達です、私たちは本でこれをするつもりです。
これで、IEの完全なコード< 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"
])
ここでは、JSファイルをロードする関数の簡単な例を示します。 関連ポイント:
-jQueryは必要ないため、最初にこれを使用してjQuery.jsファイルもロードできます。
-それはコールバックで同期しています。
-ロードされたURLの記録を含むエンクロージャーを保持するため、ネットワークの使用を回避するため、ロード回数が1回だけ保証されます。
-jQuery $ .ajax
または $ .getScript
とは異なり、noncesを使用して、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");