web-dev-qa-db-fra.com

Comment exécuter un bloc JavaScript chargé dynamiquement?

Je travaille sur une page Web où je fais un appel AJAX qui renvoie un morceau de HTML comme:

<div>
  <!-- some html -->
  <script type="text/javascript">
    /** some javascript */
  </script>
</div>

J'insère le tout dans le DOM, mais le JavaScript n'est pas en cours d'exécution. Existe-t-il un moyen de l'exécuter?

Quelques détails: je ne peux pas contrôler ce qui se trouve dans le bloc de script (donc je ne peux pas le changer en une fonction qui pourrait être appelée), j'ai juste besoin que tout le bloc soit exécuté. Je ne peux pas appeler eval sur la réponse car le JavaScript se trouve dans un plus grand bloc de HTML. Je pourrais faire une sorte de regex pour séparer le JavaScript et ensuite appeler eval dessus, mais c'est assez dégueu. Quelqu'un connaît une meilleure façon?

38
kristina

Le script ajouté en définissant la propriété innerHTML d'un élément n'est pas exécuté. Essayez de créer un nouveau div, en définissant son innerHTML, puis en ajoutant ce nouveau div au DOM. Par exemple:

 <html> 
 <head> 
 <script type = 'text/javascript'> 
 fonction addScript () 
 {
 var str = "<script> alert ('je suis ici'); <\/script>"; 
 var newdiv = document.createElement ('div'); 
 newdiv.innerHTML = str; 
 document.getElementById ('target'). appendChild (newdiv); 
} 
 </script> 
 </head> 
 <body> 
 <input type = "button" value = "add script" onclick = "addScript ()" />
 <div> hello world </div> 
 < div id = "target"> </div> 
 </body> 
 </html> 
16
Ed.

Vous n'avez pas besoin d'utiliser l'expression régulière si vous utilisez la réponse pour remplir un div ou quelque chose. Vous pouvez utiliser getElementsByTagName.

div.innerHTML = response;
var scripts = div.getElementsByTagName('script');
for (var ix = 0; ix < scripts.length; ix++) {
    eval(scripts[ix].text);
}
16
Scott Nichols

Alors que la réponse acceptée de @Ed. ne fonctionne pas sur les versions actuelles de Firefox, Google Chrome ou les navigateurs Safari, j'ai réussi à adapter son exemple afin d'invoquer des scripts ajoutés dynamiquement.

Les modifications nécessaires concernent uniquement la façon dont les scripts sont ajoutés au DOM. Au lieu de l'ajouter en tant que innerHTML, l'astuce consistait à créer un nouvel élément de script et à ajouter le contenu du script réel en tant que innerHTML à l'élément créé, puis à ajouter l'élément de script à la cible réelle.

<html>
<head>
<script type='text/javascript'>
function addScript()
{
    var newdiv = document.createElement('div');

    var p = document.createElement('p');
    p.innerHTML = "Dynamically added text";
    newdiv.appendChild(p);

    var script = document.createElement('script');
    script.innerHTML = "alert('i am here');";
    newdiv.appendChild(script);

    document.getElementById('target').appendChild(newdiv);
}
</script>
</head>
<body>
<input type="button" value="add script" onclick="addScript()"/>
<div>hello world</div>
<div id="target"></div>
</body>
</html>

Cela fonctionne pour moi sur Firefox 42, Google Chrome 48 et Safari 9.0.3

9
Roman Vottner

Une alternative est de ne pas simplement vider le retour de l'appel Ajax dans le DOM en utilisant InnerHTML.

Vous pouvez insérer chaque nœud dynamiquement, puis le script s'exécutera.

Sinon, le navigateur suppose simplement que vous insérez un nœud de texte et ignore les scripts.

Utiliser Eval est plutôt mauvais, car il nécessite une autre instance de Javascript VM pour être lancé et JIT la chaîne passée.

2
FlySwat

La meilleure méthode serait probablement d'identifier et d'évaluer le contenu du bloc de script directement via le DOM.

Je serais prudent cependant .. si vous implémentez ceci pour surmonter une limitation de certains appels hors site, vous ouvrez un trou de sécurité.

Tout ce que vous implémentez pourrait être exploité pour XSS.

1
Quintin Robinson

Vous pouvez utiliser l'une des bibliothèques Ajax populaires qui le font en natif pour vous. J'aime Prototype . Vous pouvez simplement ajouter des evalScripts: true dans le cadre de votre appel Ajax et cela se produit automatiquement.