Não é possível anexar o elemento <script>

276

Alguma idéia de por que o trecho de código abaixo não adiciona o elemento de script ao DOM?

var code = "<script></script>";
$("#someElement").append(code);
Dan Burzo
fonte
4
defina "não está funcionando" - embora eu suspeite que o problema seja que os scripts não fazem parte da árvore do dom.
Joel Coehoorn
1
Minha aposta é que o nó do script esteja sendo adicionado ao DOM, mas o navegador simplesmente não está executando o script.
Outlaw Programmer
Dan, como você realmente testou isso?
James
1
@Joel - "not working" = não tem nenhum efeito, ou seja, o código no script não é executado @Outlaw Programmer - o nó não é adicionado ao DOM @ Jimmy Sim, eu testei e não está funcionando
Dan Burzo 08/03/09

Respostas:

259

Vi problemas em que alguns navegadores não respeitam algumas alterações quando você as faz diretamente (o que significa criar o HTML a partir de texto como você está tentando com a tag de script), mas quando você faz isso com comandos internos as coisas vão melhor. Tente o seguinte:

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

De: JSON para jQuery

acrrosman
fonte
18
A tag <script> precisa ser adicionada ao próprio DOM, não ao innerHTML de um elemento existente.
Diodeus - James MacFarlane
6
@Diodeus, o innerHTML faz parte do DOM e é analisado em tempo real pelo navegador, portanto, este é um caso válido.
Cristian Toma
5
Não use apenas o acréscimo do jQuery se você realmente deseja que o elemento apareça no DOM. Use o appendChild nativo para conseguir isso.
Minqi Pan 01/10/12
8
$("#someElement")[0].appendChild( script );
Minqi Pan 01/10/12
352

A boa notícia é:

Está 100% funcionando.

Basta adicionar algo dentro da tag de script, como alert('voila!');. A pergunta certa que você talvez queira fazer, "Por que não a vi no DOM?" .

Karl Swedberg fez uma boa explicação para o comentário do visitante no site da API do jQuery . Eu não quero repetir todas as suas palavras, você pode ler diretamente aqui (Eu achei difícil de navegar através dos comentários lá) .

Todos os métodos de inserção do jQuery usam uma função domManip internamente para limpar / processar elementos antes e depois da inserção no DOM. Uma das coisas que a função domManip faz é extrair qualquer elemento de script a ser inserido e executá-lo através de uma "rotina evalScript" em vez de injetá-lo com o restante do fragmento DOM. Ele insere os scripts separadamente, avalia-os e os remove do DOM.

Acredito que um dos motivos pelos quais o jQuery faça isso é evitar erros de "Permissão Negada" que podem ocorrer no Internet Explorer ao inserir scripts em determinadas circunstâncias. Também evita inserir / avaliar repetidamente o mesmo script (que pode causar problemas) se estiver dentro de um elemento que você está inserindo e depois se mover pelo DOM.

O próximo passo é resumir as más notícias usando a .append()função para adicionar um script.


E as más notícias são ..

Você não pode depurar seu código.

Não estou brincando, mesmo se você adicionar uma debugger;palavra-chave entre a linha que deseja definir como ponto de interrupção, você acabará recebendo apenas a pilha de chamadas do objeto sem ver o ponto de interrupção no código-fonte (sem mencionar que isso Se a palavra-chave funcionar apenas no navegador da WebKit, todos os outros principais navegadores parecem omitir essa palavra-chave) .

Se você entender completamente o que seu código faz, isso será uma pequena desvantagem. Mas se não o fizer, você acabará adicionando uma debugger;palavra - chave em todo o lugar apenas para descobrir o que há de errado com o seu (ou o meu) código. De qualquer forma, existe uma alternativa, não esqueça que o javascript pode manipular nativamente o HTML DOM.


Gambiarra.

Use javascript (não jQuery) para manipular o DOM HTML

Se você não deseja perder a capacidade de depuração, pode usar a manipulação de DOM HTML nativo em javascript. Considere este exemplo:

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

Aí está, assim como nos velhos tempos, não é? E não esqueça de limpar as coisas, seja no DOM ou na memória, para todos os objetos referenciados e que não são mais necessários para evitar vazamentos de memória. Você pode considerar este código para limpar as coisas:

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

A desvantagem desta solução alternativa é que você pode adicionar acidentalmente um script duplicado, e isso é ruim. A partir daqui, você pode imitar levemente a .append()função adicionando uma verificação de objeto antes de adicionar e removendo o script do DOM logo após a adição. Considere este exemplo:

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

Dessa forma, você pode adicionar scripts com capacidade de depuração, protegidos da duplicidade de scripts. Este é apenas um protótipo, você pode expandir para o que quiser. Eu tenho usado essa abordagem e bastante satisfeito com isso. Com certeza, nunca usarei o jQuery .append()para adicionar um script.

Hendra Uzia
fonte
2
Ótima explicação, obrigado! Mas foi "UnusedReferencedObjects"?
Acre #
Obrigado. Presumo que você esteja se referindo à primeira ocorrência de "UnusedReferencedObjects", que deveria ser qualquer objeto que você criou no script carregado. Eu acho que você entende melhor se você vê o que a função DeleteObject faz, ela simplesmente exclui qualquer objeto que você passou para a função. Vou adicionar algum comentário no código para ficar claro. :)
Hendra Uzia
Super post! O exemplo de aCrosman não funcionou para mim e, depois de pronta, seu post substitui $ ("# someElement"). Append (script); com $ ("# someElement") [0] .appendChild (script); Que fixa-lo :) Thnx para o explantion
Maarten Kieft
7
$.getScriptestá embutido no jQuery.
ZzzzBov
Os SourceURLs ( blog.getfirebug.com/2009/08/11/… ) podem ajudar com problemas de depuração.
Vsevik
23

É possível carregar dinamicamente um arquivo JavaScript usando a função jQuerygetScript

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

Agora, o script externo será chamado e, se não puder ser carregado, será degradado normalmente.

Bola Branca
fonte
7
Isso não insere nada no DOM. Isso chama eval().
Nh2 17/04
20

O que você quer dizer com "não está funcionando"?

O jQuery detecta que você está tentando criar um elemento SCRIPT e executará automaticamente o conteúdo do elemento dentro do contexto global. Você está me dizendo que isso não funciona para você? -

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

Edit: Se você não está vendo o elemento SCRIPT no DOM (no Firebug, por exemplo) depois de executar o comando, porque o jQuery, como eu disse, executará o código e excluirá o elemento SCRIPT - acredito que os elementos SCRIPT sempre são anexados ao corpo ... mas de qualquer maneira - o posicionamento não tem absolutamente nenhuma influência na execução do código nessa situação.

James
fonte
17

Isso funciona:

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

Parece que o jQuery está fazendo algo inteligente com os scripts, então você precisa acrescentar o elemento html ao invés do objeto jQuery.

Darwin
fonte
2
Esta é a única solução que funciona no meu caso. Os outros problemas acima dependem do código javascript presente antecipadamente no arquivo html. Como estou adicionando código dinamicamente, esse código javascript não pode ser conhecido antecipadamente! OBRIGADO Darwin !!
tgoneil
14

Tente isto pode ser útil:

var fileref=document.createElement('script');
fileref.setAttribute("type","text/javascript");
fileref.setAttribute("src","scriptAnalytics.js");
document.getElementsByTagName("head")[0].appendChild(fileref);
Jainul Khan
fonte
9
não faço ideia por que esse cara nega, ele é o único que não é estúpido o suficiente para continuar usando o jquery para tudo!
SSpoke
Provavelmente, a maioria das respostas usa jQuery, porque na pergunta o OP está usando jQuery.
Sanbor 13/05
3

Quero fazer a mesma coisa, mas acrescentar uma tag de script em outro quadro!

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);
Julio
fonte
3
<script>
    ...
    ...jQuery("<script></script>")...
    ...
</script>

O </script>literal dentro da string finaliza o script inteiro, para evitar que "</scr" + "ipt>"possa ser usado.

Roman Odaisky
fonte
Ou não incorpore seu javascript diretamente no documento HTML. Arquivos de script externos não têm esse problema.
Ian Clelland
Sequências de escape: "\x3cscript\x3e\x3c/script\x3e". No XHTML, você só precisa inserir um bloco CDATA comentado.
Eli Gray
2
É o </que não é permitido. Veja stackoverflow.com/questions/236073/…
Gumbo
2

A adição do sourceURL ao arquivo de script ajudou conforme mencionado nesta página: https://blog.getfirebug.com/2009/08/11/give-your-eval-a-name-with-sourceurl/

  1. No arquivo de script, adicione uma instrução com sourceURL como "// @ sourceURL = foo.js"
  2. Carregue o script usando jQuery $ .getScript () e o script estará disponível na guia "sources" nas ferramentas de desenvolvimento do chrome
Naga Kiran
fonte
1

Seu script está em execução, você simplesmente não pode usá document.write-lo. Use um alerta para testá-lo e evite usá-lo document.write. As instruções do seu arquivo js com document.writenão serão executadas e o restante da função será executada.

Kunal Kinalekar
fonte
1

É isso que eu acho que é a melhor solução. O Google Analytics é injetado dessa maneira.

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); })();
dzona
fonte
1

Você não precisa do jQuery para criar um elemento DOM do script . Isso pode ser feito com a baunilha ES6 da seguinte forma:

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!'))

Ele não precisa ser envolvido em um arquivo Promise, mas isso permite que você resolva a promessa quando o script é carregado, ajudando a evitar condições de corrida para scripts de longa execução.

Josh Habdas
fonte
0

Anexe o script ao corpo:

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

Outra maneira de fazer isso se você quiser acrescentar código é usar o document.createElementmétodo, mas depois usar em .innerHTMLvez 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 );
Marc
fonte
0

Eu tentei isso uma e funciona bem. Apenas substitua o <símbolo por isso \x3C.

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

ou

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

Você pode testar o código aqui .

Andrew
fonte
0

Pode tentar assim

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

A única razão pela qual você não pode fazer isso "<script></script>"é porque a string não é permitida dentro do javascript, porque a camada DOM não pode analisar o que é js e o que é HTML.

VipinKundal
fonte
0

Eu escrevi um npmpacote que permite pegar uma string HTML, incluindo tags de script e anexá-la a um contêiner durante a execução dos scripts

Exemplo:

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)

Encontre-o aqui: https://www.npmjs.com/package/appendhtml

Lukas
fonte
-1

Basta criar um elemento analisando-o com o jQuery.

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

Exemplo de trabalho: https://plnkr.co/edit/V2FE28Q2eBrJoJ6PUEBz

Sanbor
fonte
Isso ainda tem o mesmo problema, alguns navegadores não respeitam isso.
Martin Massera
Você poderia me informar quais navegadores e qual versão do jQuery você está usando? Obrigado!
Sanbor 13/05