Dynamicznie dodaj tag skryptu za pomocą src, który może zawierać dokument.write

160

Chcę dynamicznie dołączyć tag skryptu do strony internetowej, ale nie mam kontroli nad jego src, więc src = "source.js" może wyglądać tak.

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

Teraz zwykle kładąc

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

w głowie działa dobrze, ale czy jest jakiś inny sposób na dynamiczne dodawanie source.js przy użyciu czegoś takiego jak innerHTML?

jsfiddle tego, co próbowałem

Cadell Christo
źródło
2
po godzinach zmagań z postami jest rozwiązaniem! https://github.com/krux/postscribe/
Cadell Christo
Możliwy duplikat asynchronicznego ładowania javascript z document.write
Michał Perłakowski

Odpowiedzi:

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
źródło
94

Możesz użyć tej document.createElement()funkcji w następujący sposób:

function addScript( src ) {
  var s = document.createElement( 'script' );
  s.setAttribute( 'src', src );
  document.body.appendChild( s );
}
Sirko
źródło
Jak zrobiłbyś to asynchroniczne?
UKDataGeek
3
@mobile bloke: s.async = true;
axlotl
s.setAttribute ('src', src); może być s.src src = (myślę?) Wiem, że to nie jest PCG
Brandito
67

Jest onloadfunkcja, którą można wywołać po pomyślnym załadowaniu skryptu:

function addScript( src,callback) {
  var s = document.createElement( 'script' );
  s.setAttribute( 'src', src );
  s.onload=callback;
  document.body.appendChild( s );
}
MSS
źródło
Nauczyłem się czegoś nowego. Miły!
mix3d
16

ładny mały skrypt, który napisałem, aby załadować wiele skryptów:

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

stosowanie:

scriptLoader(['a.js','b.js'], function() {
    // use code from a.js or b.js
});
EliSherer
źródło
2
Przepraszamy ... właśnie znalazłem lepszy, który zezwala na zależności stackoverflow.com/a/1867135/678780
EliSherer
5

Możesz spróbować wykonać następujący fragment kodu.

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
źródło
4

To jest praca dla mnie.

Możesz to sprawdzić.

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
źródło
3

Gdy skrypty są ładowane asynchronicznie, nie mogą wywoływać document.write. Połączenia zostaną po prostu zignorowane, a na konsoli zostanie wyświetlone ostrzeżenie.

Możesz użyć następującego kodu, aby dynamicznie załadować skrypt:

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

To podejście działa dobrze tylko wtedy, gdy źródło należy do oddzielnego pliku.

Ale jeśli masz kod źródłowy jako funkcje wbudowane, które chcesz ładować dynamicznie i chcesz dodać inne atrybuty do tagu skryptu, np. Klasa, typ itp., Pomoże Ci następujący fragment kodu:

var scriptElm = document.createElement('script');
scriptElm.setAttribute('class', 'class-name');
var inlineCode = document.createTextNode('alert("hello world")');
scriptElm.appendChild(inlineCode); 
target.appendChild(scriptElm);
malajski
źródło
2

Cóż, istnieje wiele sposobów na dołączenie dynamicznego javascript, używam tego w wielu projektach.

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

Możesz wywołać funkcję create uniwersalną, która pomoże ci załadować dowolną liczbę plików javascript. Tutaj znajduje się pełny tutorial na ten temat.

Wstawianie dynamicznego JavaScript we właściwy sposób

Shubham Maurya
źródło
2
fyi, link nie działa, nie mogłem znaleźć artykułu w innym miejscu.
user1063287
1

Jedynym sposobem na to jest zastąpienie document.writewłasnej funkcji, która będzie dodawać elementy na dole strony. Z jQuery jest całkiem proste:

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

Jeśli masz kod HTML trafiający do document.write fragmentami, jak w przykładzie pytania, musisz buforować htmlToWritesegmenty. Może coś takiego:

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

Wypróbowałem to, dołączając rekursywnie każdy skrypt

Uwaga Jeśli twoje skrypty są zależne jeden po drugim, pozycja będzie musiała być zsynchronizowana.

Zależność główna powinna znajdować się na końcu tablicy, aby początkowe skrypty mogły z niej korzystać

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
źródło
1

Wczytuje skrypty zależne od siebie we właściwej kolejności.

Oparty na odpowiedzi Satyama Pathaka , ale naprawiono obciążenie. Został uruchomiony przed załadowaniem skryptu.

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
źródło
0

Oto zminimalizowany fragment, ten sam kod, którego używa Google Analytics i Facebook Pixel:

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

Zastąp https://example.com/foo.jsścieżką do skryptu.

Mosze Simantow
źródło
0

Jedna linijka (jednak bez istotnej różnicy w stosunku do odpowiedzi powyżej):

document.body.appendChild(document.createElement('script')).src = 'source.js';
JohnW
źródło