javascript - span - ¿Se pueden insertar scripts con innerHTML?
insertar codigo html con jquery (13)
Aquí hay un método que reemplaza recursivamente todos los scripts con ejecutables:
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;
}
Ejemplo de llamada:
nodeScriptReplace(document.getElementsByTagName("body")[0]);
Intenté cargar algunos guiones en una página usando innerHTML
en un <div>
. Parece que el script se carga en el DOM, pero nunca se ejecuta (al menos en Firefox y Chrome). ¿Hay alguna manera de ejecutar scripts al insertarlos con innerHTML
?
Código de muestra:
<!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>
Aquí hay una función recursiva para establecer el innerHTML de un elemento que utilizo en nuestro servidor de anuncios:
// 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);
}
}
Puedes ver la demostración here .
Aquí hay una solución muy interesante para su problema: http://24ways.org/2005/have-your-dom-and-script-it-too
Entonces use esto en lugar de etiquetas de script:
<img src="empty.gif" onload="alert(''test'');this.parentNode.removeChild(this);" />
Etiqueta Execute (Java Script) desde innerHTML
Reemplace su elemento script con div con un atributo clase class = "javascript" y ciérrelo con </div>
No cambie el contenido que desea ejecutar (anteriormente estaba en la etiqueta de script y ahora está en la etiqueta de div)
Agrega un estilo en tu página ...
<style type="text/css"> .javascript { display: none; } </style>
Ahora ejecuta eval usando jquery (Jquery js ya debe estar incluido)
$(''.javascript'').each(function() {
eval($(this).text());
});`
Puedes explorar más here , en mi blog.
Intenta usar template y document.importNode. Aquí hay un ejemplo:
<!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>
Krasimir Tsonev tiene una gran solución que supera todos los problemas. Su método no necesita el uso de eval, por lo que no existen problemas de rendimiento ni de seguridad. Le permite establecer innerHTML cadena contiene html con js y traducirlo inmediatamente a un elemento DOM, mientras que también ejecuta las partes js existen a lo largo del código. corto, simple y funciona exactamente como lo desea.
Disfruta su solución:
http://krasimirtsonev.com/blog/article/Convert-HTML-string-to-DOM-element
Notas importantes:
- Debe envolver el elemento de destino con la etiqueta div
- Debe envolver la cadena src con la etiqueta div.
- Si escribe la cadena src directamente e incluye partes js, preste atención para escribir las etiquetas de script de cierre correctamente (con / before /) ya que esta es una cadena.
Mi solución para este problema es establecer un Mutation Observer para detectar los nodos <script></script>
y luego reemplazarlo con un nuevo nodo <script></script>
con el mismo src. Por ejemplo:
let parentNode = /* your node */ void 0
let observer = new MutationObserver(mutations=>{
mutations.map(mutation=>{
Array.from(mutation.addedNodes).map(node=>{
if ( node.parentNode == parentNode ) {
let scripts = node.getElementsByTagName(''script'')
Array.from(scripts).map(script=>{
let src = script.src
script = document.createElement(''script'')
script.src = src
return script
})
}
})
})
})
observer.observe(document.body, {childList: true, subtree: true});
Para cualquiera que todavía intente hacer esto, no, no puede inyectar una secuencia de comandos utilizando innerHTML
, pero es posible cargar una cadena en una etiqueta de secuencia de comandos usando un Blob
y URL.createObjectURL
.
He creado un ejemplo que le permite ejecutar una cadena como script y obtener las ''exportaciones'' del script devuelto a través de una promesa:
function loadScript(scriptContent, moduleId) {
// create the script tag
var scriptElement = document.createElement(''SCRIPT'');
// create a promise which will resolve to the script''s ''exports''
// (i.e., 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)
});
}
Lo simplifiqué de mi implementación real, por lo que no hay ninguna promesa de que no haya errores. Pero el principio funciona.
Si no le importa recuperar ningún valor después de que se ejecuta el script, es aún más fácil; simplemente onload
bits Promise
y onload
. Ni siquiera necesita envolver el script o crear la window.__load_script_exports_
global window.__load_script_exports_
property.
Puede crear secuencias de comandos y luego inyectar el contenido.
var g = document.createElement(''script'');
var s = document.getElementsByTagName(''script'')[0];
g.text = "alert(/"hi/");"
s.parentNode.insertBefore(g, s);
Esto funciona en todos los navegadores :)
Sí, puedes, pero tienes que hacerlo fuera del DOM y el orden debe ser el correcto.
var scr = ''<scr''+''ipt>alert("foo")</scr''+''ipt>'';
window.onload = function(){
var n = document.createElement("div");
n.innerHTML = scr;
document.body.appendChild(n);
}
... alertará ''foo''. Esto no funcionará:
document.getElementById("myDiv").innerHTML = scr;
E incluso esto no funcionará, porque el nodo se inserta primero:
var scr = ''<scr''+''ipt>alert("foo")</scr''+''ipt>'';
window.onload = function(){
var n = document.createElement("div");
document.body.appendChild(n);
n.innerHTML = scr;
}
Usé este código, está funcionando bien
var arr = MyDiv.getElementsByTagName(''script'')
for (var n = 0; n < arr.length; n++)
eval(arr[n].innerHTML)//run script inside div
Utilice $(parent).html(code)
lugar de parent.innerHTML = code
.
Lo siguiente también corrige 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.
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
})
}
eval() usar eval() para ejecutar cualquier código de secuencia de comandos que haya insertado como texto DOM.
MooTools hará esto automáticamente, y estoy seguro de que jQuery también (dependiendo de la versión. JQuery versión 1.6+ usa eval
). Esto ahorra una gran cantidad de problemas al analizar las etiquetas <script>
y escapar de su contenido, así como un montón de otros "errores".
En general, si va a eval()
usted mismo, quiere crear / enviar el código del script sin ningún tipo de marcado HTML, como <script>
, ya que estos no evaluarán eval()
correctamente.