256 votes

Peut-on insérer des scripts avec innerHTML ?

J'ai essayé de charger quelques scripts dans une page en utilisant innerHTML sur un <div> . Il semble que le script se charge dans le DOM, mais qu'il ne soit jamais exécuté (du moins dans Firefox et Chrome). Existe-t-il un moyen de faire en sorte que les script s'exécutent lorsqu'ils sont insérés à l'aide de la fonction innerHTML ?

Exemple de code :

<!DOCTYPE html>
<html>
  <body onload="document.getElementById('loader').innerHTML = '<script>alert(\'hi\')<\/script>'">
    Shouldn't an alert saying 'hi' appear?
    <div id="loader"></div>
  </body>
</html>

106voto

zombat Points 46702

Vous devez utiliser eval() pour exécuter tout code script que vous avez inséré comme texte DOM.

MooTools le fera automatiquement pour vous, et je suis sûr que jQuery le fera aussi (en fonction de la version. jQuery version 1.6 et plus utilise eval ). Cela permet d'éviter d'avoir à analyser les éléments suivants <script> et l'échappement de votre contenu, ainsi qu'un certain nombre d'autres "pièges".

En général, si vous allez eval() vous voulez créer/envoyer le code script sans aucun balisage HTML tel que <script> car ils ne seront pas eval() correctement.

12 votes

Ce que je veux vraiment faire, c'est charger un script externe, et pas seulement évaluer un script local. Ajouter une balise script avec innerHTML est beaucoup plus court que de créer un élément DOM script et de l'ajouter au corps, et j'essaie de rendre mon code aussi court que possible. Devez-vous créer les éléments dom script et les ajouter au dom plutôt que d'utiliser simplement quelque chose comme innerHTML ? Y a-t-il un moyen de faire cela avec document.write à partir d'une fonction ?

5 votes

Comme le suggère zombat, utilisez un framework Javascript pour charger le script externe, n'essayez pas de réinventer la roue. JQuery rend cela extrêmement facile, il suffit d'inclure JQuery et d'appeler : $.getScript(url). Vous pouvez également fournir une fonction de rappel qui sera exécutée une fois que le script sera chargé.

2 votes

Ariel a raison. J'apprécie d'essayer de garder votre code court, et d'ajouter un <script> tag avec innerHTML est peut-être court, mais ça ne marche pas. Ce n'est que du texte brut jusqu'à ce qu'il soit passé à travers eval() . Et malheureusement, eval() n'analyse pas les balises HTML, ce qui entraîne une série de problèmes.

106voto

SecretService Points 1469

Voici une méthode qui remplace récursivement tous les scripts par des exécutables :

function nodeScriptReplace(node) {
        if ( nodeScriptIs(node) === true ) {
                node.parentNode.replaceChild( nodeScriptClone(node) , node );
        }
        else {
                var i = -1, children = node.childNodes;
                while ( ++i < children.length ) {
                      nodeScriptReplace( children[i] );
                }
        }

        return node;
}
function nodeScriptClone(node){
        var script  = document.createElement("script");
        script.text = node.innerHTML;

        var i = -1, attrs = node.attributes, attr;
        while ( ++i < attrs.length ) {                                    
              script.setAttribute( (attr = attrs[i]).name, attr.value );
        }
        return script;
}

function nodeScriptIs(node) {
        return node.tagName === 'SCRIPT';
}

Exemple d'appel :

nodeScriptReplace(document.getElementsByTagName("body")[0]);

13 votes

Je suis un peu surpris que votre réponse soit tout en bas. IMHO, c'est la meilleure solution, cette méthode permettrait même de restreindre les scripts avec des urls ou des contenus spécifiques.

1 votes

@inf3rno le fait ou ne le fait pas ? Ça marchait avant, quelqu'un a déjà dit quelque chose de différent ?

0 votes

Quel est le but de [0] ? pouvez-vous utiliser nodeScriptReplace(document.getElementById().html) ;

97voto

user447963 Points 305

Voici une solution très intéressante à votre problème : http://24ways.org/2005/have-your-dom-and-script-it-too

Utilisez donc ceci au lieu des balises script :

<img src="empty.gif" onload="alert('test');this.parentNode.removeChild(this);" />

0 votes

Ne fonctionne pas pour moi, lorsqu'il est inséré dans un résultat d'une requête ajax : Syntax error missing ; before statement at the start of the script string.

0 votes

Comment faites-vous pour ajouter la ligne <img src....> au code de votre page ? Est-ce que vous la documentez.write() ou utilisez l'approche document.body.innerHTML+= pour cela ? Les deux échouent pour moi :(

0 votes

Il n'est pas très pratique d'écrire beaucoup de code à l'intérieur d'une onload attribut. Cela nécessite également qu'un fichier supplémentaire existe et soit chargé. La solution de momo est moins un compromis.

49voto

Pablo Moretti Points 465

Vous pouvez créer script et ensuite injecter le contenu.

var g = document.createElement('script');
var s = document.getElementsByTagName('script')[0];
g.text = "alert(\"hi\");"
s.parentNode.insertBefore(g, s);

Cela fonctionne dans tous les navigateurs :)

1 votes

Sauf s'il n'y a pas d'autres éléments script dans le document. Utilisez document.documentElement à la place.

4 votes

N'est pas nécessaire car vous écrivez un script à partir d'un autre script. <script> var g = document.createElement('script'); var s = document.getElementsByTagName('script')[0]; //reference this script g.text = "alert(\"hi\");" s.parentNode.insertBefore(g, s); </script>

3 votes

Qui dit que ça vient d'un autre script ? Vous pouvez exécuter JavaScript sans <script> éléments. Par exemple <img onerror="..." src="#"> y <body onload="..."> . Si vous voulez être technique, cela ne fonctionnera pas non plus dans les documents non-HTML/SVG en raison de l'espacement non explicite des noms.

30voto

Firas Nizam Points 340

J'ai utilisé ce code, il fonctionne bien

var arr = MyDiv.getElementsByTagName('script')
for (var n = 0; n < arr.length; n++)
    eval(arr[n].innerHTML)//run script inside div

1 votes

Merci. Cela a résolu mon problème d'ajout du code universel Disqus à une popup modale créée à l'aide du plugin Jquery TinyBox2.

4 votes

Malheureusement, cette solution ne fonctionne pas lorsque le script contient des fonctions qui seront invoquées ultérieurement.

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