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 tout dans le DOM, mais le JavaScript n'est pas lancé. Est-il un moyen de le faire fonctionner?

quelques détails: je ne peux pas contrôler ce qu'il y a dans le bloc 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 parce que le JavaScript est 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égueulasse. Quelqu'un sait d'une meilleure façon?

37
demandé sur kristina 2008-09-16 23:20:45

7 réponses

Script ajouté en définissant la propriété innerHTML d'un élément ne sera pas exécuté. Essayez de créer un nouveau div, de définir son innerHTML, puis d'ajouter ce nouveau div au DOM. Par exemple:

<html>
<head>
<script type='text/javascript'>
function addScript()
{
    var str = "<script>alert('i am here');<\/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>
15
répondu Ed. 2008-09-16 19:38:57

Vous n'avez pas à utiliser regex 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);
}
14
répondu Scott Nichols 2008-09-16 19:27:41

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

les modifications nécessaires ne sont apportées que dans la façon dont les scripts sont ajoutés au DOM. Au lieu d'ajouter que innerHTML le truc, c'était de créer un nouvel élément de script et ajouter le script réel contenu innerHTML à l'élément, puis ajouter l'élément script pour le réel cible.

<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

7
répondu Roman Vottner 2016-02-17 16:37:34

une alternative est de ne pas simplement décharger le retour de L'appel Ajax dans le DOM en utilisant InnerHTML.

vous pouvez insérer chaque noeud dynamiquement, puis le script s'exécute.

sinon, le navigateur suppose que vous insérez un noeud de texte, et ignore les scripts.

L'utilisation D'Eval est plutôt maléfique, car elle nécessite qu'une autre instance de la VM Javascript soit activée et que la chaîne passe.

2
répondu FlySwat 2008-09-16 19:36:13

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

je serais prudent, cependant.. si vous mettez en œuvre 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
répondu Quintin Robinson 2008-09-16 19:33:38

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

0
répondu Diodeus - James MacFarlane 2008-09-16 20:09:02

ci-Dessous est un peu différente de l'approche qui utilise le fait que si l'étiquette contient type="text/xml" JavaScript à l'intérieur ne va pas s'exécuter:

function preventJS(html) {
    return html.replace(/<script(?=(\s|>))/i, '<script type="text/xml" ');
}

Vous pouvez lire plus ici -JavaScript: comment empêcher L'exécution de JavaScript dans un html ajouté au DOM. Si cela fonctionne pour vous, s'il vous plaît laisser un commentaire avec des informations sur le navigateur et la version que vous avez utilisé.

-1
répondu perpetus 2013-02-06 17:06:37