No se puede agregar el elemento <script>


276

¿Alguna idea de por qué el siguiente código no agrega el elemento de script al DOM?

var code = "<script></script>";
$("#someElement").append(code);

44
defina "no funciona", aunque sospecho que el problema es que los scripts no son realmente parte del árbol dom.
Joel Coehoorn el

1
Mi apuesta es que el nodo del script se está agregando al DOM, pero el navegador simplemente no está ejecutando el script.
Outlaw Programmer

Dan, ¿cómo has probado esto?
James

1
@Joel - "no funciona" = no tiene ningún efecto, es decir, el código dentro del script no se ejecuta @Outlaw Programmer - el nodo no se agrega al DOM @Jimmy Sí, lo he probado y no funciona
Dan Burzo

Respuestas:


259

He visto problemas en los que algunos navegadores no respetan algunos cambios cuando los haces directamente (con lo que me refiero a crear el HTML a partir del texto como si estuvieras intentando con la etiqueta del script), pero cuando los haces con comandos integrados Las cosas van mejor. Prueba esto:

var script = document.createElement( 'script' );
script.type = 'text/javascript';
script.src = url;
$("#someElement").append( script );

De: JSON para jQuery


18
La etiqueta <script> debe agregarse al DOM en sí, no al innerHTML de un elemento existente.
Diodeus - James MacFarlane

66
@Diodeus el innerHTML es parte del DOM y el navegador lo analiza sobre la marcha, por lo que este es un caso válido.
Cristian Toma


55
No solo use jQuery's append si realmente desea que el elemento aparezca en el DOM. Use el appendChild nativo para lograr esto.
Minqi Pan

8
$("#someElement")[0].appendChild( script );
Minqi Pan

352

La buena noticia es:

Funciona al 100%.

Simplemente agregue algo dentro de la etiqueta del script como alert('voila!');. La pregunta correcta que tal vez quiera hacer, "¿Por qué no la vi en el DOM?" .

Karl Swedberg ha hecho una buena explicación al comentario de los visitantes en el sitio jQuery API . Yo no quiero repetir todas sus palabras, se puede leer directamente hay aquí (me pareció difícil de navegar a través de los comentarios allí) .

Todos los métodos de inserción de jQuery utilizan una función domManip internamente para limpiar / procesar elementos antes y después de que se inserten en el DOM. Una de las cosas que hace la función domManip es extraer los elementos de script que se van a insertar y ejecutarlos a través de una "rutina evalScript" en lugar de inyectarlos con el resto del fragmento DOM. Inserta los scripts por separado, los evalúa y luego los elimina del DOM.

Creo que una de las razones por las que jQuery hace esto es para evitar errores de "Permiso denegado" que pueden ocurrir en Internet Explorer al insertar scripts bajo ciertas circunstancias. También evita insertar / evaluar repetidamente el mismo script (que podría causar problemas) si está dentro de un elemento que está insertando y luego se mueve alrededor del DOM.

Lo siguiente es que resumiré cuáles son las malas noticias usando la .append()función para agregar un script.


Y la mala noticia es ...

No puedes depurar tu código.

No estoy bromeando, incluso si agrega debugger;palabras clave entre la línea que desea establecer como punto de interrupción, terminará obteniendo solo la pila de llamadas del objeto sin ver el punto de interrupción en el código fuente (sin mencionar que esto la palabra clave solo funciona en el navegador webkit, todos los demás navegadores principales parecen omitir esta palabra clave) .

Si comprende completamente lo que hace su código, esto será un inconveniente menor. Pero si no lo hace, terminará agregando una debugger;palabra clave en todo el lugar solo para descubrir qué está mal con su (o mi) código. De todos modos, hay una alternativa, no olvides que JavaScript puede manipular de forma nativa HTML DOM.


Solución alterna.

Use javascript (no jQuery) para manipular HTML DOM

Si no desea perder la capacidad de depuración, puede usar la manipulación DOM HTML nativa de JavaScript. Considere este ejemplo:

var script   = document.createElement("script");
script.type  = "text/javascript";
script.src   = "path/to/your/javascript.js";    // use this for linked script
script.text  = "alert('voila!');"               // use this for inline script
document.body.appendChild(script);

Ahí está, al igual que en los viejos tiempos, ¿no? Y no olvide limpiar las cosas, ya sea en el DOM o en la memoria, para todos los objetos a los que se hace referencia y que ya no son necesarios para evitar pérdidas de memoria. Puede considerar este código para limpiar las cosas:

document.body.removechild(document.body.lastChild);
delete UnusedReferencedObjects; // replace UnusedReferencedObject with any object you created in the script you load.

El inconveniente de esta solución es que puede agregar accidentalmente un script duplicado, y eso es malo. Desde aquí, puede imitar ligeramente la .append()función agregando una verificación de objeto antes de agregar y eliminando el script del DOM justo después de que se agregó. Considere este ejemplo:

function AddScript(url, object){
    if (object != null){
        // add script
        var script   = document.createElement("script");
        script.type  = "text/javascript";
        script.src   = "path/to/your/javascript.js";
        document.body.appendChild(script);

        // remove from the dom
        document.body.removeChild(document.body.lastChild);
        return true;
    } else {
        return false;
    };
};

function DeleteObject(UnusedReferencedObjects) {
    delete UnusedReferencedObjects;
}

De esta manera, puede agregar secuencias de comandos con capacidad de depuración mientras está a salvo de la duplicación de secuencias de comandos. Esto es solo un prototipo, puede expandirse para lo que quiera que sea. He estado usando este enfoque y estoy bastante satisfecho con esto. Efectivamente, nunca usaré jQuery .append()para agregar un script.


2
Gran explicación, gracias! ¿Pero fue "UnusedReferencedObjects"?
acme

Gracias. Supongo que se refería a la primera aparición de "UnusedReferencedObjects", que se supone que es cualquier objeto que creó en el script que carga. Supongo que entenderás mejor si ves lo que hace la función DeleteObject, simplemente elimina cualquier objeto que hayas pasado a la función. Agregaré algún comentario en el código para que quede claro. :)
Hendra Uzia

Super post! El ejemplo de aCrosman no funcionó para mí y, después de preparar su publicación, reemplacé $ ("# someElement"). Append (script); con $ ("# someElement") [0] .appendChild (script); Lo que lo solucionó :) Thnx por la explicación
Maarten Kieft

77
$.getScriptestá integrado en jQuery.
zzzzBov

SourceURLs ( blog.getfirebug.com/2009/08/11/… ) podría ayudar con problemas de depuración.
vsevik

23

Es posible cargar dinámicamente un archivo JavaScript usando la función jQuerygetScript

$ .getScript ('http://www.whatever.com/shareprice/shareprice.js', function () {
  Display.sharePrice ();
});

Ahora se llamará al script externo y, si no se puede cargar, se degradará correctamente.


77
Esto no inserta nada en el DOM. Llama eval().
nh2

20

¿Qué quieres decir con "no funciona"?

jQuery detecta que está intentando crear un elemento SCRIPT y ejecutará automáticamente el contenido del elemento dentro del contexto global. ¿Me estás diciendo que esto no funciona para ti? -

$('#someElement').append('<script>alert("WORKING");</script>');

Editar: si no está viendo el elemento SCRIPT en el DOM (en Firebug, por ejemplo) después de ejecutar el comando, es porque jQuery, como dije, ejecutará el código y luego eliminará el elemento SCRIPT: creo que los elementos SCRIPT siempre se adjuntan al cuerpo ... pero de todos modos, la ubicación no tiene absolutamente ninguna relación con la ejecución del código en esta situación.


17

Esto funciona:

$('body').append($("<script>alert('Hi!');<\/script>")[0]);

Parece que jQuery está haciendo algo inteligente con los scripts, por lo que debe agregar el elemento html en lugar del objeto jQuery.


2
Esta es la única solución que funciona en mi caso. Las otras soluciones anteriores dependen del código JavaScript presente de antemano en el archivo html. Como estoy agregando código dinámicamente, ¡ese código javascript no se puede conocer de antemano! GRACIAS Darwin !!
Tgoneil

14

Pruebe esto puede ser útil:

var fileref=document.createElement('script');
fileref.setAttribute("type","text/javascript");
fileref.setAttribute("src","scriptAnalytics.js");
document.getElementsByTagName("head")[0].appendChild(fileref);

9
¡No tengo idea de por qué este tipo es negativo, es el único que no es tan estúpido como para seguir usando jquery para todo!
SSpoke

Probablemente la mayoría de las respuestas usan jQuery porque en la pregunta el OP está usando jQuery.
sanbor

3

¡Quiero hacer lo mismo pero agregar una etiqueta de script en otro marco!

var url = 'library.js'; 
var script = window.parent.frames[1].document.createElement('script' ); 
script.type = 'text/javascript'; 
script.src = url;
$('head',window.parent.frames[1].document).append(script);

3
<script>
    ...
    ...jQuery("<script></script>")...
    ...
</script>

El </script>literal dentro de la cadena termina todo el script, para evitar que "</scr" + "ipt>"se pueda usar en su lugar.


O no incruste su javascript directamente en el documento HTML. Los archivos de script externos no tienen este problema.
Ian Clelland

Las secuencias de escape: "\x3cscript\x3e\x3c/script\x3e". En XHTML, solo necesita poner un bloque CDATA comentado.
Eli Gray

2
Es más bien lo </que no está permitido. Ver stackoverflow.com/questions/236073/…
Gumbo


1

Su script se está ejecutando, simplemente no puede usarlo document.write. Use una alerta para probarlo y evite usarlo document.write. Las declaraciones de su archivo js con document.writeno se ejecutarán y el resto de la función se ejecutará.


1

Esto es lo que creo que es la mejor solución. Google Analytics se inyecta de esta manera.

var (function(){
    var p="https:" == document.location.protocol ? "https://" : "http://";
        d=document,
        g=d.createElement('script'),
        s=d.getElementsByTagName('script')[0];
        g.type='text/javascript';
        g.src=p+'url-to-your-script.js';
        s.parentNode.insertBefore(g,s); })();

1

No necesita jQuery para crear un elemento DOM del script . Se puede hacer con vainilla ES6 así:

const script = "console.log('Did it work?')"
new Promise((resolve, reject) => {
  (function(i,s,o,g,r,a,m){
      a=s.createElement(o),m=s.getElementsByTagName(o)[0];
      a.innerText=g;
      a.onload=r;m.parentNode.insertBefore(a,m)}
  )(window,document,'script',script, resolve())
}).then(() => console.log('Sure did!'))

No necesita estar envuelto en un Promise, pero hacerlo le permite resolver la promesa cuando se carga el script, lo que ayuda a evitar condiciones de carrera para los scripts de larga ejecución.


0

Agregar script al cuerpo:

$(document).ready(function() {
    $("<script>", {  src : "bootstrap.min.js",  type : "text/javascript" }).appendTo("body");
});

0

Otra forma de hacerlo si desea agregar código es usar el document.createElementmétodo pero luego usar en .innerHTMLlugar de .src.

var script = document.createElement( 'script' );
script.type = 'text/javascript';
script.innerHTML = 'alert("Hey there... you just appended this script to the body");';
$("body").append( script );

0

He intentado esto uno y funciona bien. Simplemente reemplace el <símbolo con eso \x3C.

// With Variable
var code = "\x3Cscript>SomeCode\x3C/script>";
$("#someElement").append(code);

o

//Without Variable
$("#someElement").append("\x3Cscript>SomeCode\x3C/script>");

Puedes probar el código aquí .


0

Puede intentar así

var code = "<script></" + "script>";
$("#someElement").append(code);

La única razón por la que no puede hacerlo "<script></script>"es porque la cadena no está permitida dentro de JavaScript porque la capa DOM no puede analizar qué es js y qué es HTML.


0

Escribí un npmpaquete que le permite tomar una cadena HTML, incluidas las etiquetas de secuencia de comandos y agregarla a un contenedor mientras ejecuta las secuencias de comandos

Ejemplo:

import appendHtml from 'appendhtml';

const html = '<p>Hello</p><script src="some_js_file.js"></script>'; 
const container = document.getElementById('some-div');

await appendHtml(html, container);

// appendHtml returns a Promise, some_js_file.js is now loaded and executed (note the await)

Encuéntralo aquí: https://www.npmjs.com/package/appendhtml


-1

Simplemente cree un elemento analizándolo con jQuery.

<div id="someElement"></div>
<script>
    var code = "<script>alert(123);<\/script>";
    $("#someElement").append($(code));
</script>

Ejemplo de trabajo: https://plnkr.co/edit/V2FE28Q2eBrJoJ6PUEBz


Esto todavía tiene el mismo problema, algunos navegadores no lo respetan.
Martin Massera

¿Podría decirme qué navegadores y qué versión de jQuery está utilizando? ¡Gracias!
sanbor
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.