Comment insérer dynamiquement une balise <script> via jQuery après le chargement de la page?

101

J'ai des problèmes pour que cela fonctionne. J'ai d'abord essayé de définir mes balises de script en tant que chaînes, puis d'utiliser jquery replaceWith () pour les ajouter au document après le chargement de la page:

var a = '<script type="text/javascript">some script here</script>';
$('#someelement').replaceWith(a);

Mais j'ai eu des erreurs littérales de chaîne sur ce var. J'ai ensuite essayé d'encoder la chaîne comme:

var a = '&left;script type="text/javascript"&gt;some script here&lt;\/script&gt;';

mais envoyer cela aux replaceWith()sorties juste cette chaîne au navigateur.

Quelqu'un peut-il me dire comment vous feriez pour ajouter dynamiquement une <script>balise dans le navigateur après le chargement de la page, idéalement via jQuery?

Doug
la source
Pouvez-vous expliquer ce que vous essayez d'accomplir en ajoutant une <script>balise au document?
Pointy
La réponse de @ Rocket est la meilleure, mais si vous vouliez vraiment ajouter un script en ligne à partir d'une chaîne, vous le passeriez simplement à la eval()fonction. Mais l'utilisation de eval()suggère presque toujours qu'il existe une meilleure façon de faire ce que vous essayez de faire.
Nick
nous essayons de reporter le chargement des publicités tierces jusqu'à la fin de la page. ces publicités sont appelées via 2 balises de script, donc je voulais exécuter une fonction après le chargement de la page qui les lance dynamiquement.
Doug
2
Tous les scripts tiers ne sont pas conçus pour être différés. Si le script utilise document.writeet que vous l'appelez après le chargement de la page, il détruira la page.
bobince
1
Pourquoi ne pas importer ces balises dans les <iframe>éléments? Vous pouvez différer la définition de l' <iframe>URL jusqu'à ce que vous soyez prêt.
Pointy

Réponses:

103

Vous pouvez placer le script dans un fichier séparé, puis l'utiliser $.getScriptpour le charger et l'exécuter.

Exemple:

$.getScript("test.js", function(){
    alert("Running test.js");
});
Fusée Hazmat
la source
2
merci, mais cela va-t-il le coller dans le DOM? Je me rends compte que j'ai omis cette information importante, que j'ai besoin que la balise de script soit insérée dans le DOM, évaluée, à quel point elle renvoie le code d'annonce tiers à afficher sur notre site dans un <div> spécifique.
Doug
1
$.getScriptva juste charger un fichier .js via AJAX et l'exécuter. Le script n'a pas besoin d'être dans le DOM pour pouvoir accéder à un div sur votre page.
Rocket Hazmat
6
Mais avec $.getScript()le script devra être sur le même domaine ou le domaine distant et le navigateur devront prendre en charge CORS.
hippietrail
14
@hippietrail Ce n'est en fait pas vrai. Il insère simplement une balise de script simple, qui ne nécessite pas CORS ou le même domaine. J'utilise cela pour raccourcir le code de chargement de Google Analytics par exemple, et il se charge très bien. Dans les coulisses, le code jquery qui s'exécute est assez similaire à l'extrait de code GA, en fait.
Chris Moschini
39
Étant donné que la réponse de @hippietrail attirera le plus l'attention avec ses 4 votes positifs, il convient de préciser clairement qu'il est incorrect. Comme le soulignent les documents jQuery dans leurs $.ajaxnotes: "Les requêtes de script et JSONP ne sont pas soumises aux mêmes restrictions de politique d'origine." source . En d'autres termes, $.getScriptpeut extraire des fichiers .js d'autres domaines, pas seulement les vôtres .
EleventyOne
64

Essayez ce qui suit:

<script type="text/javascript">
// Use any event to append the code
$(document).ready(function() 
{
    var s = document.createElement("script");
    s.type = "text/javascript";
    s.src = "http://scriptlocation/das.js";
    // Use any selector
    $("head").append(s);
});

http://api.jquery.com/append

Bassem
la source
4
+1 pour utiliser appendpour ajouter un script. Append provoque même une évaluation immédiate du script en ligne (exactement ce dont j'avais besoin). Merci
Gone Coding
1
Je finis par avoir beaucoup de problèmes dans IE8 / 9 avec cette approche. À savoir les erreurs de débordement de pile. J'ai eu recours à la méthode $ .getScript () ci-dessous pour que ce travail fonctionne à tous les niveaux.
zmonteca
1
Oui @jcoffland cela a été écrit en octobre 2010 :)
Bassem
Si la page contenant ce code est chargée à l'aide d'AJAX, le navigateur lancera un avertissement «Synchronous XMLHttpRequest on the main thread is deprecated en raison de ses effets néfastes sur l'expérience de l'utilisateur final».
Rajshekar Reddy
@Reddy Excellent commentaire. Cela a été publié en octobre 2010, je suis sûr que cette méthode n'est plus une approche valide / recommandée, les utilisateurs doivent procéder à leur propre discrétion.
Bassem
34

Voici la bonne façon de le faire avec JQuery moderne (2014):

$(function () {
  $('<script>')
    .attr('type', 'text/javascript')
    .text('some script here')
    .appendTo('head');
})

ou si vous voulez vraiment remplacer un div, vous pouvez faire:

$(function () {
  $('<script>')
    .attr('type', 'text/javascript')
    .text('some script here')
    .replaceAll('#someelement');
});
jcoffland
la source
3
Ou à la place .text ('un script ici') vous pouvez écrire .attr ('src', 'path_to_your_js_file')
Serhii Maksymchuk
12

Un moyen plus simple est:

$('head').append('<script type="text/javascript" src="your.js"></script>');

Vous pouvez également utiliser ce formulaire pour charger des css.

Iman
la source
6
Vous voudrez peut-être éviter de mettre la chaîne </script>dans votre source car cela peut causer des problèmes d'analyse: stackoverflow.com/questions/236073/…
iX3
2
échapper au dernier a /fait l'affaire pour moi:$('head').append('<script src="your.js"><\/script>');
jerik
5

Cette réponse est techniquement similaire ou égale à ce que jcoffland a répondu. Je viens d'ajouter une requête pour détecter si un script est déjà présent ou non. J'en ai besoin car je travaille dans un site intranet avec quelques modules, dont certains partagent des scripts ou apportent les leurs, mais ces scripts n'ont pas besoin d'être chargés à chaque fois. J'utilise cet extrait depuis plus d'un an dans un environnement de production, cela fonctionne comme un charme. Commentant à moi-même: Oui je sais, il serait plus correct de demander si une fonction existe ... :-)

if (!$('head > script[src="js/jquery.searchable.min.js"]').length) {
    $('head').append($('<script />').attr('src','js/jquery.searchable.min.js'));
}
ddlab
la source
btw. Je fais de même avec les feuilles de style: if (! $ ('Head> link [href = "widgets / css / widgets.css"]'). Length) {$ ('head'). Append ($ ('<link / > '). attr (' rel ',' styleheet '). attr (' href ',' widgets / css / widgets.css '));}
ddlab
2

Il existe une solution de contournement qui ressemble plus à un hack et je suis d'accord que ce n'est pas la façon la plus élégante de le faire, mais fonctionne à 100%:

Dites que votre réponse AJAX est quelque chose comme

<b>some html</b>
<script>alert("and some javscript")

Notez que j'ai sauté la balise de fermeture exprès. Ensuite, dans le script qui charge ce qui précède, procédez comme suit:

$.ajax({
    url: "path/to/return/the-above-js+html.php",
    success: function(newhtml){
        newhtml += "<";
        newhtml += "/script>";
        $("head").append(newhtml);
    }
});

Ne me demandez pas pourquoi :-) C'est l'une de ces choses auxquelles je suis arrivé à la suite d'essais désespérés presque aléatoires et d'échecs.

Je n'ai pas de suggestions complètes sur son fonctionnement, mais il est intéressant de noter que cela ne fonctionnera PAS si vous ajoutez la balise de fermeture sur une ligne.

Dans des moments comme ceux-ci, j'ai l'impression d'avoir réussi à diviser par zéro.

Cendre
la source
3
Cela ne fonctionnera pas si la balise de script de fermeture est en un seul morceau, car le navigateur la voit comme la balise de fermeture de votre script au lieu d'une chaîne littérale.
Fini le codage le
1
<\/script>serait valide cependant
SP le
Je pense que le point de @ TrueBlueAussie était en réponse à votre commentaire "Ne me demandez pas pourquoi ... mais assez intéressant, cela ne fonctionnera PAS si vous ajoutez la balise de fermeture sur une ligne." Il a expliqué pourquoi afin que tous les lecteurs qui souhaiteraient une meilleure réponse que «je ne sais pas» puissent la trouver plus facilement. Voir aussi: javascript.crockford.com/script.html
iX3
1
@Sathvik a raison, d'après ce lien. Le commentaire d'Ash semble avoir été une réponse à celui qui a été supprimé.
Arlen Beiler le
2

Exemple:

var a = '<script type="text/javascript">some script here</script>';
$('#someelement').replaceWith(a);

Cela devrait marcher. Je l'ai essayé; même résultat. Mais quand j'ai utilisé ceci:

var length = 1;
var html = "";
for (var i = 0; i < length; i++) {
    html += '<div id="codeSnippet"></div>';
    html += '<script type="text/javascript">';
    html += 'your script here';
    html += '</script>';
}
$('#someElement').replaceWith(a);

Cela a fonctionné pour moi.

Edit: j'ai oublié le #someelement(btw je pourrais vouloir utiliser à #someElementcause des conventions)

La chose la plus importante ici est le + = donc le html est ajouté et non remplacé.

Laissez un commentaire si cela n'a pas fonctionné. J'aimerais vous aider!

santinobonora
la source
2

Voici un moyen beaucoup plus clair - pas besoin de jQuery - qui ajoute un script comme dernier enfant de <body>:

document.body.innerHTML +='<script src="mycdn.js"><\/script>'

Mais si vous souhaitez ajouter et charger des scripts, utilisez la méthode de Rocket Hazmat .

Gagik Sargsyan
la source
-4

Si vous essayez d'exécuter du JavaScript généré dynamiquement, vous seriez légèrement mieux en utilisant eval. Cependant, JavaScript est un langage tellement dynamique que vous ne devriez vraiment pas en avoir besoin.

Si le script est statique, alors la getScriptsuggestion de Rocket est la voie à suivre.

Magnar
la source