Adicione dinamicamente a tag de script com src, que pode incluir document.write

161

Quero incluir dinamicamente uma tag de script em uma página da Web, mas não tenho controle sobre o src;

document.write('<script type="text/javascript">')
document.write('alert("hello world")')
document.write('</script>')
document.write('<p>goodbye world</p>')

Agora normalmente colocando

<script type="text/javascript" src="source.js"></script> 

na cabeça funciona bem, mas existe alguma outra maneira de adicionar o source.js dinamicamente usando algo como innerHTML?

jsfiddle do que eu tentei

Cadell Christo
fonte
2
depois de horas de luta com postscribe é a solução! https://github.com/krux/postscribe/
Cadell Christo
Possível duplicata do assíncrono carregando javascript com document.write
Michał Perłakowski

Respostas:

210
var my_awesome_script = document.createElement('script');

my_awesome_script.setAttribute('src','http://example.com/site.js');

document.head.appendChild(my_awesome_script);
dmp
fonte
94

Você pode usar a document.createElement()função assim:

function addScript( src ) {
  var s = document.createElement( 'script' );
  s.setAttribute( 'src', src );
  document.body.appendChild( s );
}
Sirko
fonte
Como você faria isso assíncrono?
UKDataGeek
3
@ cara móvel: s.async = true;
precisa saber é o seguinte
s.setAttribute ('src', src); poderia ser s.src = src (eu acho?) eu sei que isso não é PCG
Brandito
68

Existe a onloadfunção que pode ser chamada quando o script é carregado com êxito:

function addScript( src,callback) {
  var s = document.createElement( 'script' );
  s.setAttribute( 'src', src );
  s.onload=callback;
  document.body.appendChild( s );
}
MSS
fonte
1
Aprendeu algo novo. Agradável!
mix3d
16

um bom pequeno script que escrevi para carregar vários scripts:

function scriptLoader(scripts, callback) {

    var count = scripts.length;

    function urlCallback(url) {
        return function () {
            console.log(url + ' was loaded (' + --count + ' more scripts remaining).');
            if (count < 1) {
                callback();
            }
        };
    }

    function loadScript(url) {
        var s = document.createElement('script');
        s.setAttribute('src', url);
        s.onload = urlCallback(url);
        document.head.appendChild(s);
    }

    for (var script of scripts) {
        loadScript(script);
    }
};

uso:

scriptLoader(['a.js','b.js'], function() {
    // use code from a.js or b.js
});
EliSherer
fonte
2
Desculpe ... apenas encontrou um melhor que permitem dependências stackoverflow.com/a/1867135/678780
EliSherer
5

Você pode tentar seguir o snippet de código.

function addScript(attribute, text, callback) {
    var s = document.createElement('script');
    for (var attr in attribute) {
        s.setAttribute(attr, attribute[attr] ? attribute[attr] : null)
    }
    s.innerHTML = text;
    s.onload = callback;
    document.body.appendChild(s);
}

addScript({
    src: 'https://www.google.com',
    type: 'text/javascript',
    async: null
}, '<div>innerHTML</div>', function(){});
vaenow
fonte
4

Isso é trabalho para mim.

Você pode verificá-lo.

var script_tag = document.createElement('script');
script_tag.setAttribute('src','https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js');
document.head.appendChild(script_tag);
window.onload = function() {
    if (window.jQuery) {  
        // jQuery is loaded  
        alert("ADD SCRIPT TAG ON HEAD!");
    } else {
        // jQuery is not loaded
        alert("DOESN'T ADD SCRIPT TAG ON HEAD");
    }
}

jd savaj
fonte
3

Quando os scripts são carregados de forma assíncrona, eles não podem chamar document.write. As chamadas serão simplesmente ignoradas e um aviso será gravado no console.

Você pode usar o seguinte código para carregar o script dinamicamente:

var scriptElm = document.createElement('script');
scriptElm.src = 'source.js';
document.body.appendChild(scriptElm);

Essa abordagem funciona bem apenas quando sua fonte pertence a um arquivo separado.

Mas se você tiver o código-fonte como funções embutidas que deseja carregar dinamicamente e adicionar outros atributos à tag de script, por exemplo, classe, tipo, etc., o seguinte trecho o ajudará:

var scriptElm = document.createElement('script');
scriptElm.setAttribute('class', 'class-name');
var inlineCode = document.createTextNode('alert("hello world")');
scriptElm.appendChild(inlineCode); 
target.appendChild(scriptElm);
malaio
fonte
2

Bem, existem várias maneiras de incluir o javascript dinâmico. Eu uso este em muitos dos projetos.

var script = document.createElement("script")
script.type = "text/javascript";
//Chrome,Firefox, Opera, Safari 3+
script.onload = function(){
console.log("Script is loaded");
};
script.src = "file1.js";
document.getElementsByTagName("head")[0].appendChild(script);

Você pode chamar criar uma função universal que pode ajudá-lo a carregar quantos arquivos javascript forem necessários. Há um tutorial completo sobre isso aqui.

Inserindo o Javascript Dinâmico da maneira certa

Shubham Maurya
fonte
2
fyi, o link não está funcionando, não encontrei o artigo em outro lugar.
user1063287
1

a única maneira de fazer isso é substituí-lo document.writepor sua própria função, que acrescentará elementos ao final da página. É bem simples com o jQuery:

document.write = function(htmlToWrite) {
  $(htmlToWrite).appendTo('body');
}

Se você tiver o html vindo para document.write em partes como o exemplo da pergunta, será necessário armazenar em buffer os htmlToWritesegmentos. Talvez algo assim:

document.write = (function() {
  var buffer = "";
  var timer;
  return function(htmlPieceToWrite) {
    buffer += htmlPieceToWrite;
    clearTimeout(timer);
    timer = setTimeout(function() {
      $(buffer).appendTo('body');
      buffer = "";
    }, 0)
  }
})()
Scott Jungwirth
fonte
1

Eu tentei anexando recursivamente cada script

Nota Se seus scripts dependem um após o outro, a posição precisará estar sincronizada.

A Dependência Principal deve estar em último na matriz, para que os scripts iniciais possam usá-la

const scripts = ['https://www.gstatic.com/firebasejs/6.2.0/firebase-storage.js', 'https://www.gstatic.com/firebasejs/6.2.0/firebase-firestore.js', 'https://www.gstatic.com/firebasejs/6.2.0/firebase-app.js']
let count = 0

  
 const recursivelyAddScript = (script, cb) => {
  const el = document.createElement('script')
  el.src = script
  if(count < scripts.length) {
    count ++
    el.onload = recursivelyAddScript(scripts[count])
    document.body.appendChild(el)
  } else {
    console.log('All script loaded')
    return
  }
}
 
  recursivelyAddScript(scripts[count])

Satyam Pathak
fonte
1

Carrega scripts que dependem um do outro com a ordem correta.

Com base na resposta de Satyam Pathak , mas corrigiu a carga. Foi acionado antes do carregamento do script.

const scripts = ['https://www.gstatic.com/firebasejs/6.2.0/firebase-storage.js', 'https://www.gstatic.com/firebasejs/6.2.0/firebase-firestore.js', 'https://www.gstatic.com/firebasejs/6.2.0/firebase-app.js']
let count = 0

  
 const recursivelyAddScript = (script, cb) => {
  const el = document.createElement('script')
  el.src = script
  if(count < scripts.length) {
    count ++
    el.onload = () => recursivelyAddScript(scripts[count])
    document.body.appendChild(el)
  } else {
    console.log('All script loaded')
    return
  }
}
 
  recursivelyAddScript(scripts[count])

Kolorafa
fonte
0

Aqui está um snippet reduzido, o mesmo código que o Google Analytics e o Facebook Pixel usam:

!function(e,s,t){(t=e.createElement(s)).async=!0,t.src="https://example.com/foo.js",(e=e.getElementsByTagName(s)[0]).parentNode.insertBefore(t,e)}(document,"script");

Substitua https://example.com/foo.jspelo seu caminho de script.

Moshe Simantov
fonte
0

Um one-liner (embora não haja diferença essencial para as respostas acima):

document.body.appendChild(document.createElement('script')).src = 'source.js';
JohnW
fonte