inner ejemplos javascript dom eval innerhtml

ejemplos - javascript get inner html



Ejecutar elementos<script> insertados con.innerHTML (17)

Tengo un script que inserta algo de contenido en un elemento usando innerHTML .

El contenido podría ser, por ejemplo:

<script type="text/javascript">alert(''test'');</script> <strong>test</strong>

El problema es que el código dentro de la etiqueta <script> no se ejecuta. Busqué en Google un poco, pero no hubo soluciones aparentes. Si $(element).append(content); el contenido usando jQuery $(element).append(content); las partes del script obtuvieron una eval antes de ser inyectadas en el DOM.

¿Alguien ha recibido un fragmento de código que ejecuta todos los elementos del <script> ? El código de jQuery era un poco complejo, así que no pude entender cómo se hizo.

Editar :

Al echar un vistazo al código de jQuery he logrado averiguar cómo lo hace jQuery, lo que dio como resultado el siguiente código:

Demo: <div id="element"></div> <script type="text/javascript"> function insertAndExecute(id, text) { domelement = document.getElementById(id); domelement.innerHTML = text; var scripts = []; ret = domelement.childNodes; for ( var i = 0; ret[i]; i++ ) { if ( scripts && nodeName( ret[i], "script" ) && (!ret[i].type || ret[i].type.toLowerCase() === "text/javascript") ) { scripts.push( ret[i].parentNode ? ret[i].parentNode.removeChild( ret[i] ) : ret[i] ); } } for(script in scripts) { evalScript(scripts[script]); } } function nodeName( elem, name ) { return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase(); } function evalScript( elem ) { data = ( elem.text || elem.textContent || elem.innerHTML || "" ); var head = document.getElementsByTagName("head")[0] || document.documentElement, script = document.createElement("script"); script.type = "text/javascript"; script.appendChild( document.createTextNode( data ) ); head.insertBefore( script, head.firstChild ); head.removeChild( script ); if ( elem.parentNode ) { elem.parentNode.removeChild( elem ); } } insertAndExecute("element", "<scri"+"pt type=''text/javascript''>document.write(''This text should appear as well.'')</scr"+"ipt><strong>this text should also be inserted.</strong>"); </script>



Aquí está mi solución en un proyecto reciente.

<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Sample</title> </head> <body> <h1 id="hello_world">Sample</h1> <script type="text/javascript"> var div = document.createElement("div"); var t = document.createElement(''template''); t.innerHTML = "Check Console tab for javascript output: Hello world!!!<br/><script type=''text/javascript'' >console.log(''Hello world!!!'');<//script>"; for (var i=0; i < t.content.childNodes.length; i++){ var node = document.importNode(t.content.childNodes[i], true); div.appendChild(node); } document.body.appendChild(div); </script> </body> </html>


Aquí hay un script más corto y eficiente que también funciona para scripts con la propiedad src :

function insertAndExecute(id, text) { document.getElementById(id).innerHTML = text; var scripts = Array.prototype.slice.call(document.getElementById(id).getElementsByTagName("script")); for (var i = 0; i < scripts.length; i++) { if (scripts[i].src != "") { var tag = document.createElement("script"); tag.src = scripts[i].src; document.getElementsByTagName("head")[0].appendChild(tag); } else { eval(scripts[i].innerHTML); } } }

Nota: mientras que eval puede causar una vulnerabilidad de seguridad si no se usa correctamente, es mucho más rápido que crear una etiqueta de script sobre la marcha.


Es más fácil usar jquery $(parent).html(code) lugar de parent.innerHTML = code :

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 }) }

Esto también funciona con scripts que usan document.write y scripts cargados a través del atributo src . Lamentablemente, incluso esto no funciona con las secuencias de comandos de Google AdSense.


Extendiéndose fuera de Larry. Lo hice buscar recursivamente todo el bloque y los nodos de los niños.
La secuencia de comandos ahora también invocará las secuencias de comandos externas que se especifiquen con el parámetro src. Los guiones se anexan al encabezado en lugar de insertarse y colocarse en el orden en que se encuentran. Así que, específicamente, se preservan los guiones de órdenes. Y cada script se ejecuta de forma sincronizada, de forma similar a como el navegador maneja la carga DOM inicial. Entonces, si tiene un bloque de script que llama a jQuery desde un CDN y que el siguiente nodo de script usa jQuery ... ¡No hay problema! Oh y etiqueté los scripts anexados con una identificación serializada basada en lo que estableciste en el parámetro de etiqueta para que puedas encontrar lo que se agregó con este script.

exec_body_scripts: function(body_el, tag) { // Finds and executes scripts in a newly added element''s body. // Needed since innerHTML does not run scripts. // // Argument body_el is an element in the dom. function nodeName(elem, name) { return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase(); }; function evalScript(elem, id, callback) { var data = (elem.text || elem.textContent || elem.innerHTML || "" ), head = document.getElementsByTagName("head")[0] || document.documentElement; var script = document.createElement("script"); script.type = "text/javascript"; if (id != '''') { script.setAttribute(''id'', id); } if (elem.src != '''') { script.src = elem.src; head.appendChild(script); // Then bind the event to the callback function. // There are several events for cross browser compatibility. script.onreadystatechange = callback; script.onload = callback; } else { try { // doesn''t work on ie... script.appendChild(document.createTextNode(data)); } catch(e) { // IE has funky script nodes script.text = data; } head.appendChild(script); callback(); } }; function walk_children(node) { var scripts = [], script, children_nodes = node.childNodes, child, i; if (children_nodes === undefined) return; for (i = 0; i<children_nodes.length; i++) { child = children_nodes[i]; if (nodeName(child, "script" ) && (!child.type || child.type.toLowerCase() === "text/javascript")) { scripts.push(child); } else { var new_scripts = walk_children(child); for(j=0; j<new_scripts.length; j++) { scripts.push(new_scripts[j]); } } } return scripts; } var i = 0; function execute_script(i) { script = scripts[i]; if (script.parentNode) {script.parentNode.removeChild(script);} evalScript(scripts[i], tag+"_"+i, function() { if (i < scripts.length-1) { execute_script(++i); } }); } // main section of function if (tag === undefined) tag = ''tmp''; var scripts = walk_children(body_el); execute_script(i); }


Gracias al guión de Larry, que funcionó perfectamente en IE10, esto es lo que he usado:

$(''#'' + id)[0].innerHTML = result; $(''#'' + id + " script").each(function() { this.text = this.text || $(this).text();} );


La secuencia de comandos de OP no funciona en IE 7. Con la ayuda de SO, aquí hay una secuencia de comandos que hace:

exec_body_scripts: function(body_el) { // Finds and executes scripts in a newly added element''s body. // Needed since innerHTML does not run scripts. // // Argument body_el is an element in the dom. function nodeName(elem, name) { return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase(); }; function evalScript(elem) { var data = (elem.text || elem.textContent || elem.innerHTML || "" ), head = document.getElementsByTagName("head")[0] || document.documentElement, script = document.createElement("script"); script.type = "text/javascript"; try { // doesn''t work on ie... script.appendChild(document.createTextNode(data)); } catch(e) { // IE has funky script nodes script.text = data; } head.insertBefore(script, head.firstChild); head.removeChild(script); }; // main section of function var scripts = [], script, children_nodes = body_el.childNodes, child, i; for (i = 0; children_nodes[i]; i++) { child = children_nodes[i]; if (nodeName(child, "script" ) && (!child.type || child.type.toLowerCase() === "text/javascript")) { scripts.push(child); } } for (i = 0; scripts[i]; i++) { script = scripts[i]; if (script.parentNode) {script.parentNode.removeChild(script);} evalScript(scripts[i]); } };


No debe usar la propiedad innerHTML sino el método appendChild del nodo: un nodo en un árbol de documentos [HTML DOM]. De esta manera, más tarde puede llamar a su código inyectado.

Asegúrese de comprender que node.innerHTML no es lo mismo que node.appendChild . Es posible que desee pasar algún tiempo en la Referencia de cliente de Javascript para obtener más detalles y el DOM. Espero que lo siguiente ayude ...

La inyección de muestra funciona:

<html> <head> <title>test</title> <script language="javascript" type="text/javascript"> function doOnLoad(){ addScript(''inject'',"function foo(){ alert(''injected''); }"); } function addScript(inject,code){ var _in = document.getElementById(''inject''); var scriptNode = document.createElement(''script''); scriptNode.innerHTML = code; _in.appendChild(scriptNode); } </script> </head> <body onload="doOnLoad();"> <div id="header">some content</div> <div id="inject"></div> <input type="button" onclick="foo(); return false;" value="Test Injected" /> </body> </html>

Saludos,


Prueba este fragmento:

function stripAndExecuteScript(text) { var scripts = ''''; var cleaned = text.replace(/<script[^>]*>([/s/S]*?)<//script>/gi, function(){ scripts += arguments[1] + ''/n''; return ''''; }); if (window.execScript){ window.execScript(scripts); } else { var head = document.getElementsByTagName(''head'')[0]; var scriptElement = document.createElement(''script''); scriptElement.setAttribute(''type'', ''text/javascript''); scriptElement.innerText = scripts; head.appendChild(scriptElement); head.removeChild(scriptElement); } return cleaned; }; var scriptString = ''<scrip'' + ''t + type="text/javascript">alert(/'test/');</scr'' + ''ipt><strong>test</strong>''; document.getElementById(''element'').innerHTML = stripAndExecuteScript(scriptString);


Prueba esto, funciona para mí en Chrome, Safari y Firefox:

var script = document.createElement(''script''); script.innerHTML = ''console.log("hi")''; document.body.appendChild(script); --> logs "hi"

Sin embargo, una cosa a tener en cuenta es que NO se ejecutará el siguiente script div-anidado:

var script = document.createElement(''div''); script.innerHTML = ''<script>console.log("hi")</script>''; document.body.appendChild(script); --> doesn''t log anything

Para que se ejecute un script, debe crearse como un nodo y luego anexarse ​​como un elemento secundario. Incluso puede agregar un script dentro de un div previamente inyectado y se ejecutará (me he encontrado con esto antes cuando intento que el código del servidor de anuncios funcione):

var div = document.createElement(''div''); div.id = ''test-id''; document.body.appendChild(div); var script = document.createElement(''script''); script.innerHTML = ''console.log("hi")''; document.getElementById(''test-id'').appendChild(script); --> logs "hi"


Prueba la función eval ().

data.newScript = ''<script type="text/javascript">//my script...</script>'' var element = document.getElementById(''elementToRefresh''); element.innerHTML = data.newScript; eval(element.firstChild.innerHTML);

Este es un ejemplo real de un proyecto que estoy desarrollando. Gracias a esta post


Puede echar un vistazo a esta publicación . El código podría verse así:

var actualDivToBeUpdated = document.getElementById(''test''); var div = document.createElement(''div''); div.innerHTML = ''<script type="text/javascript">alert("test");<//script>''; var children = div.childNodes; actualDivToBeUpdated.innerHTML = ''''; for(var i = 0; i < children.length; i++) { actualDivToBeUpdated.appendChild(children[i]); }


Solo haz:

document.body.innerHTML = ''<img src="../images/loaded.gif" alt="" onload="alert(/'test/');this.parentNode.removeChild(this);" />'';


Una solución sin usar "eval":

var setInnerHtml = function(elm, html) { elm.innerHTML = html; var scripts = elm.getElementsByTagName("script"); // If we don''t clone the results then "scripts" // will actually update live as we insert the new // tags, and we''ll get caught in an endless loop var scriptsClone = []; for (var i = 0; i < scripts.length; i++) { scriptsClone.push(scripts[i]); } for (var i = 0; i < scriptsClone.length; i++) { var currentScript = scriptsClone[i]; var s = document.createElement("script"); // Copy all the attributes from the original script for (var j = 0; j < currentScript.attributes.length; j++) { var a = currentScript.attributes[j]; s.setAttribute(a.name, a.value); } s.appendChild(document.createTextNode(currentScript.innerHTML)); currentScript.parentNode.replaceChild(s, currentScript); } }

Esto esencialmente clona la etiqueta de secuencia de comandos y luego reemplaza la etiqueta de secuencia de comandos bloqueada con la nueva etiqueta generada, lo que permite la ejecución.


Versión ES6 simplificada de la respuesta de @ joshcomley con un ejemplo

http://plnkr.co/edit/MMegiu?p=preview

var setInnerHtml = function(elm, html) { elm.innerHTML = html; Array.from(elm.querySelectorAll("script")).forEach(function(el) { let newEl = document.createElement("script"); Array.from(el.attributes).forEach(function(el) { newEl.setAttribute(el.name, el.value) }); newEl.appendChild(document.createTextNode(el.innerHTML)); el.parentNode.replaceChild(newEl, el); }) }

Uso

el.innerHTML = HTML; // does not run <script> in HTML setInnerHTML(el, HTML); // execute <script> in HTML


scriptNode.innerHTML = code no funcionó para IE. Lo único que hay que hacer es reemplazar con scriptNode.text = code y funciona bien


function insertHtml(id, html) { var ele = document.getElementById(id); ele.innerHTML = html; var codes = ele.getElementsByTagName("script"); for(var i=0;i<codes.length;i++) { eval(codes[i].text); } }

Funciona en Chrome en mi proyecto