2008-09-16 8 views
34

Je travaille sur une page Web où je fais un appel AJAX qui retourne un morceau de HTML comme:Comment exécutez-vous un bloc JavaScript chargé dynamiquement?

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

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

Quelques détails: Je ne peux pas contrôler ce qu'il y a dans le bloc de script (donc je ne peux pas le changer pour 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 plutôt dégueulasse. Quelqu'un sait-il un meilleur moyen?

Répondre

14

Le script ajouté en définissant la propriété innerHTML d'un élément n'est pas exécuté. Essayez de créer une nouvelle div, en définissant innerHTML, puis en ajoutant cette nouvelle 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> 
+1

Ce script ne fonctionne pas dans IE 7. IE 7 semble avoir un bug avec la fonction appendChild. – Eddie

+2

Ne fonctionne pas, en utilisant google chrome 26. – prashn64

+3

ne fonctionne pas sur n'importe quel navigateur moderne (firefox, chrome, safari) – Roy

14

Vous n'avez pas besoin d'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); 
} 
+7

cela semble très vulnérable aux attaques par injection et d'autres vecteurs ... –

1

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

Je serais cependant prudent .. si vous implémentez cela 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.

+0

-moi si je me trompe, mais le Comme je comprends les vulnérabilités XSS dans ce type de situations, c'est un problème si vous craignez que quelqu'un puisse accéder au compte en ligne de quelqu'un d'autre, et ainsi être capable de voler des informations sensibles, mais si les utilisateurs ne peuvent pas connectez-vous sur le site alors ce n'est pas un souci. –

2

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

Vous pouvez insérer chaque noeud dynamiquement, puis le script s'exécutera. Dans le cas contraire, le navigateur suppose simplement que vous insérez un nœud de texte et ignore les scripts. L'utilisation d'Eval est plutôt mauvaise, car elle nécessite qu'une autre instance de la VM Javascript soit allumée et JIT la chaîne passée.

+12

Ce serait très bien si vous expliquiez comment insérer chaque nœud dynamiquement. – mandza

0

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

-1

Ci-dessous est un peu différente approche qui utilise le fait que si balise contient type = « text/xml » JavaScript dans ne sera pas exécuté:

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

Vous pouvez en lire plus ici - JavaScript: How to prevent execution of JavaScript within a html being added to the DOM. Si cela fonctionne pour vous, s'il vous plaît laissez ici un commentaire avec des informations quel navigateur et la version que vous avez utilisé.

5

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

Les modifications nécessaires concernent uniquement la manière dont les scripts sont ajoutés à DOM.Au lieu de l'ajouter comme innerHTML, l'astuce consistait à créer un nouvel élément de script et à ajouter le contenu du script 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

Questions connexes