Les scripts peuvent-ils être insérés avec innerHTML?

J'ai essayé de charger des scripts dans une page utilisant innerHTML sur un <div> . Il semble que le script se charge dans le DOM, mais il n'est jamais exécuté (au moins dans Firefox et Chrome). Existe-t-il un moyen d'exécuter des scripts lors de l'insertion de 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> 

Vous devez utiliser eval () pour exécuter n'importe quel code de script que vous avez inséré en tant que texte DOM.

MooTools le fera automatiquement pour vous, et je suis sûr que jQuery serait aussi bien (selon la version. JQuery version 1.6+ utilise eval ). Cela économise beaucoup de difficultés à analyser les balises <script> et à échapper à votre contenu, ainsi qu'un tas d'autres "getchas".

En général, si vous allez eval() vous-même, vous souhaitez créer / envoyer le code script sans balisage HTML tel que <script> , car ce ne sera pas eval() correctement.

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 de script:

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

Voici une méthode qui remplace de façon récurrente tous les scripts avec des exécutables:

 function nodeScriptReplace(node) { if ( nodeScriptIs(node) === true ) { node.parentNode.replaceChild( nodeScriptClone(node) , node ); } else { var i = 0; var children = node.childNodes; while ( i < children.length ) { nodeScriptReplace( children[i++] ); } } return node; } function nodeScriptIs(node) { return node.tagName === 'SCRIPT'; } function nodeScriptClone(node){ var script = document.createElement("script"); script.text = node.innerHTML; for( var i = node.attributes.length-1; i >= 0; i-- ) { script.setAttribute( node.attributes[i].name, node.attributes[i].value ); } return script; } 

Exemple d'appel:

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

Vous pouvez créer un 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 🙂

J'ai utilisé ce code, ça fonctionne bien

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

Krasimir Tsonev a une excellente solution pour résoudre tous les problèmes. Sa méthode n'a pas besoin d'utiliser eval, donc il n'y a pas de performance ni de problèmes de sécurité. Il vous permet de définir la chaîne innerHTML contient html avec js et de le traduire immédiatement sur un élément DOM alors qu'il exécute également les parties js existent le long du code. Court, simple, et fonctionne exactement comme vous le souhaitez.

Profitez de sa solution:

http://krasimirtsonev.com/blog/article/Convert-HTML-string-to-DOM-element

Notes IMPORTANTES:

  1. Vous devez envelopper l'élément cible avec la balise div
  2. Vous devez envelopper la chaîne src avec la balise div.
  3. Si vous écrivez directement la chaîne src et qu'elle inclut des pièces js, prenez l'attention d'écrire correctement les balises de script de fermeture (avec \ avant /) car il s'agit d'une chaîne.

Utilisez $(parent).html(code) au lieu de parent.innerHTML = code .

Ce qui suit corrige également les scripts qui utilisent document.write et les scripts chargés via l'attribut src . Malheureusement, cela ne fonctionne pas toujours avec les scripts Google AdSense.

 var oldDocumentWrite = document.write; var oldDocumentWriteln = document.writeln; try { document.write = function(code) { $(parent).append(code); } document.writeln = function(code) { document.write(code + "<br/>"); } $(parent).html(html); } finally { $(window).load(function() { document.write = oldDocumentWrite document.writeln = oldDocumentWriteln }) } 

La source

Pour ceux qui essaient toujours de le faire, non, vous ne pouvez pas injecter un script à l'aide de innerHTML , mais il est possible de charger une chaîne dans une étiquette de script à l'aide d'un Blob et d' URL.createObjectURL .

J'ai créé un exemple qui vous permet d'exécuter une chaîne en tant que script et d'obtenir les «exportations» du script renvoyées par une promesse:

 function loadScript(scriptContent, moduleId) { // create the script tag var scriptElement = document.createElement('SCRIPT'); // create a promise which will resolve to the script's 'exports' // (ie, the value returned by the script) var promise = new Promise(function(resolve) { scriptElement.onload = function() { var exports = window["__loadScript_exports_" + moduleId]; delete window["__loadScript_exports_" + moduleId]; resolve(exports); } }); // wrap the script contents to expose exports through a special property // the promise will access the exports this way var wrappedScriptContent = "(function() { window['__loadScript_exports_" + moduleId + "'] = " + scriptContent + "})()"; // create a blob from the wrapped script content var scriptBlob = new Blob([wrappedScriptContent], {type: 'text/javascript'}); // set the id attribute scriptElement.id = "__loadScript_module_" + moduleId; // set the src attribute to the blob's object url // (this is the part that makes it work) scriptElement.src = URL.createObjectURL(scriptBlob); // append the script element document.body.appendChild(scriptElement); // return the promise, which will resolve to the script's exports return promise; } ... function doTheThing() { // no evals loadScript('5 + 5').then(function(exports) { // should log 10 console.log(exports) }); } 

Je l'ai simplifié grâce à ma mise en œuvre réelle, donc aucune promesse qu'il n'y ait pas de bogues. Mais le principe fonctionne.

Si vous ne vous souciez pas de récupérer une valeur après le script, c'est encore plus facile; Il suffit de laisser onload bits Promise and onload . Vous n'avez même pas besoin d'envelopper le script ou de créer la window.__load_script_exports_ globale window.__load_script_exports_ property.

Oui, vous pouvez, mais vous devez le faire en dehors du DOM et l'ordre doit être correct.

 var scr = '<scr'+'ipt>alert("foo")</scr'+'ipt>'; window.onload = function(){ var n = document.createElement("div"); n.innerHTML = scr; document.body.appendChild(n); } 

… va alerter 'foo'. Cela ne fonctionnera pas:

 document.getElementById("myDiv").innerHTML = scr; 

Et même cela ne fonctionnera pas, car le nœud est inséré en premier:

 var scr = '<scr'+'ipt>alert("foo")</scr'+'ipt>'; window.onload = function(){ var n = document.createElement("div"); document.body.appendChild(n); n.innerHTML = scr; } 

Exécuter (Java Script) tag depuis innerHTML

Remplacez votre élément de script par div ayant une classe d'attribut de classe = "javascript" et fermez-le avec </div>

Ne modifiez pas le contenu que vous souhaitez exécuter (auparavant, il était dans la balise de script et maintenant il est dans la balise div)

Ajoutez un style dans votre page …

<style type="text/css"> .javascript { display: none; } </style>

Maintenant, exécutez eval en utilisant jquery (Jquery js devrait déjà être inclus)

  $('.javascript').each(function() { eval($(this).text()); });` 

Vous pouvez explorer plus ici , sur mon blog.

Voici une fonction récursive pour définir innerHTML d'un élément que j'utilise dans notre serveur publicitaire:

 // o: container to set the innerHTML // html: html text to set. // clear: if true, the container is cleared first (children removed) function setHTML(o, html, clear) { if (clear) o.innerHTML = ""; // Generate a parseable object with the html: var dv = document.createElement("div"); dv.innerHTML = html; // Handle edge case where innerHTML contains no tags, just text: if (dv.children.length===0){ o.innerHTML = html; return; } for (var i = 0; i < dv.children.length; i++) { var c = dv.children[i]; // n: new node with the same type as c var n = document.createElement(c.nodeName); // copy all attributes from c to n for (var j = 0; j < c.attributes.length; j++) n.setAttribute(c.attributes[j].nodeName, c.attributes[j].nodeValue); // If current node is a leaf, just copy the appropriate property (text or innerHTML) if (c.children.length == 0) { switch (c.nodeName) { case "SCRIPT": if (c.text) n.text = c.text; break; default: if (c.innerHTML) n.innerHTML = c.innerHTML; break; } } // If current node has sub nodes, call itself recursively: else setHTML(n, c.innerHTML, false); o.appendChild(n); } } 

Vous pouvez voir la démonstration ici .

Ajoutez le tag en tête après avoir placé du texte dans innerHTML et il fonctionnera

J'ai essayé cela et ça marche. Merci @mwilcox.

 var maint = document.getElementById("maint"); maint.innerHTML = ''; var inner = '<form >'+ 'add new member:-<br>'+ '<input type="text" name="namea" placeholder="enter ur name">'+ '</form >'; maint.innerHTML = inner;