180 votes

Charger dynamiquement un fichier JavaScript

Comment charger de manière fiable et dynamique un fichier JavaScript ? Cette volonté peut être utilisée pour mettre en œuvre un module ou un composant qui, lorsqu'il est "initialisé", charge dynamiquement tous les scripts de la bibliothèque JavaScript nécessaires à la demande.

Le client qui utilise le composant n'est pas obligé de charger tous les fichiers de la bibliothèque script (et d'insérer manuellement <script> dans leur page web) qui mettent en œuvre ce composant - juste le fichier script du composant 'principal'.

Comment les bibliothèques JavaScript classiques y parviennent-elles (Prototype, jQuery, etc.) ? Ces outils fusionnent-ils plusieurs fichiers JavaScript en une seule version 'build' redistribuable d'un fichier script ? Ou effectuent-ils un chargement dynamique de script auxiliaires de 'bibliothèque' ?

Un complément à cette question : existe-t-il un moyen de gérer l'événement après le chargement d'un fichier JavaScript inclus dynamiquement ? Le prototype a document.observe pour les événements à l'échelle du document. Exemple :

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

Quels sont les événements disponibles pour un élément script ?

86voto

aemkei Points 4602

Vous pouvez créer un élément script de façon dynamique, à l'aide des éléments suivants Prototypes :

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

Le problème ici est que nous ne savons pas quand le fichier script externe est entièrement chargé.

Nous voulons souvent avoir notre code dépendant sur la ligne suivante et nous aimons écrire quelque chose comme :

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

Il existe un moyen intelligent d'injecter des dépendances script sans avoir besoin de callbacks. Il suffit de tirer le script via une balise demande AJAX synchrone et évalue le script au niveau global.

Si vous utilisez Prototype, la méthode script.load ressemble à ceci :

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

1 votes

Que puis-je faire pour que cela fonctionne pour les domaines croisés ? (chargement de script à partir de http://web.archive.org/web/20140905044059/http://www.howtocr‌​eate.co.uk/operaStu‌​ff/userjs/aagmfunct‌​ions.js )

1 votes

1 votes

@Ciastopiekarz : Je ne contrôle pas web.archive.org .

29voto

travis Points 14676

J'ai utilisé un une version beaucoup moins compliquée récemment con 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>

Il fonctionne parfaitement dans tous les navigateurs que j'ai testés : IE6/7, Firefox, Safari, Opera.

Mise à jour : Version sans 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>

26 votes

C'est génial... sauf si vous essayez de charger Jquery.

1 votes

Il semble que jQuery va intégrer le plugin Require dans jQuery Core pour une prochaine version : plugins.jquery.com/projet/require

1 votes

Une façon encore meilleure d'utiliser jQuery est d'utiliser $.getScript . Voir ma réponse.

20voto

palehorse Points 8268

J'ai fait à peu près la même chose que toi Adam, mais avec une légère modification pour m'assurer que j'ajoutais à l'adresse de l'utilisateur. head élément pour faire le travail. J'ai simplement créé un include (code ci-dessous) pour gérer à la fois les fichiers script et CSS.

Cette fonction vérifie également que le script ou le fichier CSS n'a pas déjà été chargé dynamiquement. Elle ne vérifie pas les valeurs codées à la main et il y aurait peut-être eu une meilleure façon de le faire, mais elle a rempli son rôle.

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

0 votes

Sans plus de contexte, j'ai peur de ne pas avoir de suggestions. Le code ci-dessus fonctionne tel quel, il a été tiré directement d'un projet fonctionnel.

5 votes

@palehorse, Mike et Muhd, ont raison, cela peut fonctionner dans votre projet, mais c'est parce que les variables "includedFile" et "Array" doivent être définies ailleurs dans votre projet, ce code seul ne fonctionnera pas, il serait peut-être préférable de l'éditer pour qu'il puisse fonctionner en dehors du contexte de votre projet, ou au moins ajouter un commentaire expliquant ce que sont ces variables non définies (type etc.)

14voto

Naveed Points 4948

Une autre réponse géniale

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

2 votes

Que puis-je faire pour que cela fonctionne pour les domaines croisés ? (chargement de script à partir de http://web.archive.org/web/20140905044059/http://www.howtocr‌​eate.co.uk/operaStu‌​ff/userjs/aagmfunct‌​ions.js )

9voto

Adam Points 8165

Voici quelques exemples de code que j'ai trouvés... quelqu'un a-t-il une meilleure méthode ?

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

0 votes

Que puis-je faire pour que cela fonctionne pour les domaines croisés ? (chargement de script à partir de http://web.archive.org/web/20140905044059/http://www.howtocr‌​eate.co.uk/operaStu‌​ff/userjs/aagmfunct‌​ions.js )

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X