Cum poți fiabil și dinamic încărca un fișier JavaScript? Acest lucru va poate fi utilizat pentru a implementa un modul sau componentă care, atunci când 'inițializat' componenta va încărca dinamic toate necesare bibliotecă JavaScript script-uri la cerere.
Clientul care utilizează componenta e't este necesar pentru a încărca toate biblioteca script files (și introduce manual `<script> tag-uri în pagina lor de web) care pun în aplicare această componentă - doar 'principal' componenta fișier script.
Cum de masă biblioteci JavaScript realiza acest lucru (Prototype, jQuery, etc.)? Aceste instrumente fuziona mai multe fișiere JavaScript într-un singur redistributable 'construi' versiune a unui fișier script? Sau fac orice încărcare dinamică auxiliare 'biblioteca' script?
Un plus la această întrebare: există o modalitate de a se ocupe de eveniment, după o dinamic inclus fișier JavaScript este încărcat? Prototipul a document.observa
pentru document evenimentelor. Exemplu:
document.observe("dom:loaded", function() {
// initially hide all containers for tab content
$$('div.tabcontent').invoke('hide');
});
Care sunt disponibile evenimente pentru un element de script?
S-ar putea scrie dinamice tag-uri script (folosind Prototip):
new Element("script", {src: "myBigCodeLibrary.js", type: "text/javascript"});
Problema aici este că nu știm atunci când extern fișier script este complet încărcată.
De multe ori am vrut noastre depind de codul de pe următoarea linie și vrea să scrie ceva de genul:
if (iNeedSomeMore) {
Script.load("myBigCodeLibrary.js"); // includes code for myFancyMethod();
myFancyMethod(); // cool, no need for callbacks!
}
Există un mod inteligent de a injecta script dependențe fără a fi nevoie de callback. Trebuie pur și simplu să trageți de script prin intermediul unui sincron cerere AJAX și eval script-ul la nivel global.
Dacă utilizați Prototip Script-ul.metoda de încărcare arată astfel:
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);
}
};
Nu există nici o import / include / necesită în javascript, dar există două modalități principale de a realiza ceea ce vrei:
1 - puteți încărca cu un apel AJAX apoi utilizați eval.
Acesta este modul cel mai simplu, dar's a limitat la domeniul dvs. pentru a Javascript setările de siguranță, și folosind eval se deschide ușa de la bug-uri și hacks.
2 - Adăugați o etichetă script cu script-ul URL-ul în HTML.
Cu siguranta cel mai bun mod de a merge. Aveți posibilitatea să încărcați script-ul chiar de la un server extern, și-l's curat ca tine utilizați browser-ul parser pentru a evalua cod. Puteți pune <script /> tag-ul în cap de la pagina de web, sau în partea de jos a corpului.
Ambele soluții sunt discutate și ilustrate aici.
Acum, există o mare problemă trebuie să știi despre. A face asta înseamnă că la distanță de încărcare codul. Browserele web moderne va încărca fișierul și să păstreze de executare curentă script pentru că au încărcat totul în mod asincron pentru a îmbunătăți performanțele.
Aceasta înseamnă că, dacă utilizați aceste trucuri direct, ai castigat't fi capabil de a utiliza poze recent încărcate cod următoarea linie după ce a cerut să fie încărcate, pentru că va fi încă de încărcare.
E. G : my_lovely_script.js conține 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
Apoi reîncărcați pagina lovind F5. Și funcționează! Confuz...
Deci, ce să fac despre el ?
Ei bine, puteți folosi hack autorul sugerează în link-ul l-am dat. În rezumat, pentru oameni într-o grabă, el folosește ro eveniment pentru a rula o funcție de apel invers, atunci când script-ul este încărcat. Astfel încât să puteți pune tot codul, folosind telecomanda de bibliotecă, în funcție de apel invers. 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);
}
Apoi scrii codul pe care doriți să utilizați DUPĂ scenariul este încărcat într-o funcție lambda :
var myPrettyCode = function() {
// here, do what ever you want
};
Apoi executați toate că :
loadScript("my_lovely_script.js", myPrettyCode);
Ok, am luat-o. Dar's o durere de a scrie toate astea.
Ei bine, în acest caz, puteți folosi ca întotdeauna fantastic gratuit jQuery cadru, care să te facă același lucru într-o singură linie :
$.getScript("my_lovely_script.js", function() {
alert("Script loaded and executed.");
// here you can use anything you defined in the loaded script
});
Am folosit-o mult mai puțin complicat versiune recent cu 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>
Ea a lucrat mare în fiecare browser-ul l-am testat în: IE6/7, Firefox, Safari, Opera.
Actualizare: jQuery-mai puțin versiune:
<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>
Am făcut practic același lucru pe care ai făcut-o Adam, dar cu o ușoară modificare pentru a face sigur că am fost adăugarea de tag-ul cap pentru a obține locuri de muncă făcut. Pur și simplu am creat o includ funcția (codul de mai jos) să se ocupe de ambele script și css fișiere.
Această funcție verifică, de asemenea, să asigurați-vă că script sau un fișier CSS n't fost deja încărcate dinamic. Nu a verifica pentru mână valori codificate și se poate să fi fost o modalitate mai bună de a face asta, dar ea a servit scopul.
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 );
}
un alt răspuns minunat
$.getScript("my_lovely_script.js", function(){
alert("Script loaded and executed.");
// here you can use anything you defined in the loaded script
});
Aici este un exemplu de cod I'am gasit... are cineva o modalitate mai bună?
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);
}
Dacă aveți jQuery încărcate deja, ar trebui să utilizați $.getScript.
Acest lucru are un avantaj față de alte răspunsuri în care aveți o construit în funcție de apel invers (pentru a garanta script-ul este încărcat înainte dependentă de codul ruleaza), și puteți controla cache.
Tocmai a aflat despre o caracteristică de mare în YUI 3 (în momentul de scris, disponibil în versiune preview). Puteți introduce cu ușurință dependențe de YUI biblioteci și la "extern" module (ceea ce cauti), fără prea mult cod: YUI Loader.
De asemenea, răspunsurile la a doua întrebare în ceea ce privește funcția de a fi numit cât mai curând modul extern este încărcat.
Exemplu:
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(...);
}
});
A lucrat perfect pentru mine și are avantajul de gestionarea dependențelor. Se referă la YUI documentația pentru un exemplu cu YUI 2 calendar.
am'am folosit o altă soluție am gasit pe net ... asta este sub creativecommons și verifică dacă sursa a fost inclus înainte de a apela funcția ...
puteți găsi fișierul de aici: 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);
}
}
}
nimeni nu avea o modalitate mai bună?
Cred că doar adăugarea de script-ul pentru organism ar fi mai ușor apoi adăugându-l la ultimul nod de pe pagina. Ce zici de asta:
function include(url) {
var s = document.createElement("script");
s.setAttribute("type", "text/javascript");
s.setAttribute("src", url);
document.body.appendChild(s);
}
Dacă doriți o SINCRONIZARE încărcare script-ul, aveți nevoie pentru a adăuga script de text direct în HTML tag-ul CAP. Adăugarea de ca <script src="myscript.js"> va declanșa o ASINCRON încărcați. Pentru a încărca script de text din fișier extern sincron, utilizarea XHR. Mai jos o scurtă probă (se folosesc piese de alte răspunsuri la aceste și alte posturi):
/*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()); });
Nu's a propus un nou ECMA standard numit dinamic import, recent încorporate în Chrome și Safari.
const moduleSpecifier = './dir/someModule.js';
import(moduleSpecifier)
.then(someModule => someModule.foo()); // executes foo method in someModule
Păstrați-l frumos, scurt, simplu, și de intretinut! :]
// 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]);
}
}
Acest cod este pur și simplu un scurt exemplu funcțional care - ar putea necesită suplimentare funcționalitate caracteristică pentru suport complet pe orice (sau dat) platforma.
jquery rezolvate asta pentru mine cu ei .append() funcția
/*
pentru(var script în bibliotecă){ $('cap').append('<script type="text/javascript" src="' + dirPath + biblioteca[script] + '"></script>'); }
Pentru a Utiliza - in capul tau html/php/etc după ce importați jquery.js tu va include doar un singur dosar ca astfel să se încarce în întregime de bibliotecă adăugarea-l la cap...
<script type="text/javascript" src="project.library.js"></script>
Aici este unul simplu, cu apel invers și ANUME de sprijin:
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');
});
Știu că răspunsul meu este cam târziu pentru această întrebare, dar, aici este un articol mare în www.html5rocks.com - se arunca cu capul Adânc în apele tulburi de încărcare script .
În articolul respectiv s-a concluzionat că, în ceea ce privește browser-ul de sprijin, cel mai bun mod de a încărca dinamic fișier JavaScript fără blocarea redarea de conținut este următorul mod:
Având în vedere te'am patru scenarii nume `script1.js, script2.js, script3.js, script4.js atunci poti sa o faci cu aplicarea 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);
});
Acum, Spec spune: pentru a Descărca împreună, executa la comanda cât mai curând toate download.
Firefox < 3.6, Opera spune: nu am idee de ce acest "async" e, dar doar așa se întâmplă să execute script-uri adăugate prin JS în ordinea în care acestea sunt adăugate.
Safari 5.0 spune: am înțeles "asincron", dar nu înțeleg setarea la "false" cu JS. Voi executa script-uri de indata ce ajung la sol, în orice ordine.
IE < 10 spune: Nici o idee despre "asincron", dar există o soluție, folosind "onreadystatechange".
Totul altceva spune: eu sunt prietenul tău, o să facem asta ca la carte.
Acum, codul complet cu IE < 10 soluție:
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>');
}
}
Câteva trucuri și minimizare mai târziu, 362 bytes
!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"
])
Ceva de genul asta...
<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>
Aici un exemplu simplu pentru o funcție pentru a încărca fișiere, JS fișiere. Aspecte relevante:
$.ajax "sau"$.getScript
poti folosi pedofili, rezolvând astfel problemele cu CSP nesigur-inline
. Doar folosi proprietatea script-ul.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);
}
};
}();
Acum ai folosi pur și simplu prin
getScriptOnce("url_of_your_JS_file.js");