Nie można dołączyć elementu <script>

276

Masz pojęcie, dlaczego poniższy fragment kodu nie dodaje elementu skryptu do DOM?

var code = "<script></script>";
$("#someElement").append(code);
Dan Burzo
źródło
4
zdefiniuj „nie działa” - choć podejrzewam, że problem polega na tym, że skrypty nie są tak naprawdę częścią drzewa dom.
Joel Coehoorn
1
Założę się, że węzeł skryptu jest dodawany do DOM, ale przeglądarka po prostu nie wykonuje skryptu.
Outlaw Programmer
Dan, jak to przetestowałeś?
James
1
@Joel - „nie działa” = nie ma żadnego efektu, tj. Kod w skrypcie nie jest wykonywany @Outlaw Programmer - węzeł nie został dodany do DOM @Jimmy Tak, przetestowałem go i nie działa
Dan Burzo

Odpowiedzi:

259

Widziałem problemy, w których niektóre przeglądarki nie szanują niektórych zmian, gdy robisz je bezpośrednio (przez co mam na myśli tworzenie kodu HTML z tekstu, tak jak próbujesz ze znacznikiem script), ale kiedy robisz to za pomocą wbudowanych poleceń wszystko idzie lepiej. Spróbuj tego:

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

Od: JSON dla jQuery

akrobata
źródło
18
Tag <script> należy dodać do samego DOM, a nie do innerHTML istniejącego elementu.
Diodeus - James MacFarlane
6
@Diodeus innerHTML jest częścią DOM i jest analizowany w locie przez przeglądarkę, więc jest to prawidłowy przypadek.
Cristian Toma
5
Nie używaj tylko aplikacji jQuery, jeśli naprawdę chcesz, aby element pojawił się w DOM. Aby to osiągnąć, użyj natywnego appendChild.
Minqi Pan
8
$("#someElement")[0].appendChild( script );
Minqi Pan
352

Dobrą wiadomością jest:

To działa w 100%.

Po prostu dodaj coś do znacznika skryptu, np alert('voila!');. Właściwe pytanie, które możesz zadać, być może: „Dlaczego nie widziałem go w DOM?” .

Karl Swedberg wyjaśnił komentarz gościa na stronie API jQuery . I nie chcą powtórzyć wszystkie jego słowa można odczytać bezpośrednio tam tutaj (I trudno było poruszać się po komentarzach tam) .

Wszystkie metody wstawiania jQuery używają funkcji domManip wewnętrznie do czyszczenia / przetwarzania elementów przed i po ich wstawieniu do DOM. Jedną z rzeczy, którą robi funkcja domManip, jest wyciąganie wszelkich elementów skryptu, które mają zostać wstawione, i uruchamianie ich za pomocą „procedury evalScript” zamiast wstrzykiwania ich resztą fragmentu DOM. Wstawia skrypty osobno, ocenia je, a następnie usuwa z DOM.

Uważam, że jednym z powodów, dla których jQuery to robi, jest uniknięcie błędów „Odmowa zezwolenia”, które mogą wystąpić w Internet Explorerze podczas wstawiania skryptów w określonych okolicznościach. Pozwala to również uniknąć wielokrotnego wstawiania / oceny tego samego skryptu (co mogłoby potencjalnie powodować problemy), jeśli znajduje się w elemencie zawierającym, który wstawiasz, a następnie poruszasz się po DOM.

Następną rzeczą jest, podsumuję złe wieści, używając .append()funkcji do dodania skryptu.


A złą wiadomością jest ...

Nie możesz debugować swojego kodu.

Nie żartuję, nawet jeśli dodasz debugger;słowo kluczowe między wierszem, który chcesz ustawić jako punkt przerwania, skończysz na otrzymywaniu tylko stosu wywołań obiektu, nie widząc punktu przerwania w kodzie źródłowym (nie wspominając o tym słowo kluczowe działa tylko w przeglądarce webkit, wszystkie inne główne przeglądarki wydają się pomijać to słowo kluczowe) .

Jeśli w pełni rozumiesz, co robi Twój kod, będzie to niewielka wada. Ale jeśli tego nie zrobisz, w końcu dodasz debugger;słowo kluczowe, aby dowiedzieć się, co jest nie tak z twoim (lub moim) kodem. W każdym razie istnieje alternatywa, nie zapominaj, że javascript może natywnie manipulować HTML DOM.


Obejście

Użyj javascript (nie jQuery) do manipulowania HTML DOM

Jeśli nie chcesz utracić możliwości debugowania, możesz użyć natywnej manipulacji DOM HTML w javascript. Rozważ ten przykład:

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

Oto jest, tak jak za dawnych czasów, prawda? I nie zapomnij wyczyścić rzeczy w DOM lub w pamięci dla wszystkich obiektów, do których istnieje odwołanie i które nie są już potrzebne, aby zapobiec wyciekom pamięci. Możesz wziąć pod uwagę ten kod, aby wyczyścić rzeczy:

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

Wadą tego obejścia jest to, że możesz przypadkowo dodać duplikat skryptu i to źle. Stąd możesz nieco naśladować .append()funkcję, dodając weryfikację obiektu przed dodaniem i usuwając skrypt z DOM zaraz po jego dodaniu. Rozważ ten przykład:

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

W ten sposób możesz dodać skrypt z funkcją debugowania, jednocześnie bezpieczny przed duplikatem skryptu. To tylko prototyp, który możesz rozbudować o to, co chcesz. Korzystam z tego podejścia i jestem z tego całkiem zadowolony. Na pewno nigdy nie użyję jQuery, .append()aby dodać skrypt.

Hendra Uzia
źródło
2
Świetne wyjaśnienie, dzięki! Ale czy było „UnusedReferencedObjects”?
acme
Dzięki. Zakładam, że odnosiłeś się do pierwszego wystąpienia „UnusedReferencedObjects”, który miał być dowolnym obiektem utworzonym w ładowanym skrypcie. Myślę, że lepiej zrozumiesz, jeśli zobaczysz, co robi funkcja DeleteObject, po prostu usuwa każdy obiekt przekazany do tej funkcji. Dodaję komentarz w kodzie, aby było jasne. :)
Hendra Uzia
Super post! Przykład aCrosmana nie działał dla mnie i po przygotowaniu twojego postu zastąpiłem $ („# someElement”). Append (skrypt); z $ („# someElement”) [0] .appendChild (skrypt); Które to naprawiło :) Dzięki za eksplozję
Maarten Kieft
7
$.getScriptjest wbudowany w jQuery.
zzzzBov,
Źródłowe adresy URL ( blog.getfirebug.com/2009/08/11/… ) mogą pomóc w rozwiązywaniu problemów.
vsevik
23

Możliwe jest dynamiczne ładowanie pliku JavaScript za pomocą funkcji jQuerygetScript

$ .getScript („http://www.whokolwiek.com/shareprice/shareprice.js”, function () {
  Display.sharePrice ();
});

Teraz zewnętrzny skrypt zostanie wywołany, a jeśli nie będzie można go załadować, z wdziękiem się pogorszy.

Bila rozpoczynająca
źródło
7
To nie wstawia niczego do DOM. Wzywa eval().
nh2 17.04.13
20

Co masz na myśli mówiąc „nie działa”?

jQuery wykrywa, że ​​próbujesz utworzyć element SCRIPT i automatycznie uruchomi zawartość tego elementu w kontekście globalnym. Mówisz mi, że to nie działa dla ciebie? -

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

Edycja: Jeśli nie widzisz elementu SCRIPT w DOM (na przykład w Firebug) po uruchomieniu polecenia, ponieważ jQuery, jak powiedziałem, uruchomi kod, a następnie usunie element SCRIPT - Wierzę, że elementy SCRIPT są zawsze dołączane do treści ... ale w każdym razie - umieszczenie nie ma absolutnie żadnego wpływu na wykonanie kodu w tej sytuacji.

James
źródło
17

To działa:

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

Wygląda na to, że jQuery robi coś sprytnego ze skryptami, więc musisz dodać element HTML zamiast obiektu jQuery.

Darwin
źródło
2
To jest jedyne rozwiązanie, które działa w moim przypadku. Pozostałe powyższe sol'ny zależą od kodu javascript obecnego wcześniej w pliku HTML. Ponieważ dodam kod dynamicznie, takiego kodu javascript nie można poznać z góry! DZIĘKI Darwin !!
tgoneil
14

Spróbuj to może być pomocne:

var fileref=document.createElement('script');
fileref.setAttribute("type","text/javascript");
fileref.setAttribute("src","scriptAnalytics.js");
document.getElementsByTagName("head")[0].appendChild(fileref);
Jainul Khan
źródło
9
nie mam pojęcia, dlaczego ten facet neguje, że jest jedynym, który nie jest na tyle głupi, by używać wszystkiego we wszystkim!
SSpoke
Prawdopodobnie większość odpowiedzi używa jQuery, ponieważ w pytaniu OP używa jQuery.
sanbor
3

Chcę zrobić to samo, ale dołączyć znacznik skryptu w innej ramce!

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
źródło
3
<script>
    ...
    ...jQuery("<script></script>")...
    ...
</script>

</script>Ciągu Ciąg dosłownych kończy cały scenariusz, aby uniknąć sytuacji, "</scr" + "ipt>"może być stosowany zamiast.

Roman Odaisky
źródło
Lub nie osadzaj javascript bezpośrednio w dokumencie HTML. Zewnętrzne pliki skryptów nie mają tego problemu.
Ian Clelland
Sekwencje: "\x3cscript\x3e\x3c/script\x3e". W XHTML wystarczy wstawić skomentowany blok CDATA.
Eli Gray,
2
Raczej </nie jest to dozwolone. Zobacz stackoverflow.com/questions/236073/…
Gumbo
1

Twój skrypt jest wykonywany, po prostu nie możesz document.writez niego korzystać. Użyj alertu, aby go przetestować i unikaj używania document.write. Instrukcje pliku js z document.writenie zostaną wykonane, a reszta funkcji zostanie wykonana.

Kunal Kinalekar
źródło
1

To jest, moim zdaniem, najlepsze rozwiązanie. Google Analytics jest wstrzykiwany w ten sposób.

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

Nie potrzebujesz jQuery, aby utworzyć element DOM skryptu . Można to zrobić za pomocą wanilii ES6 tak:

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

Nie musi być zawinięty w Promise, ale pozwala to spełnić obietnicę, gdy skrypt zostanie załadowany, co pomoże zapobiec warunkom wyścigowym dla długo działających skryptów.

Josh Habdas
źródło
0

Dołącz skrypt do treści:

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

Innym sposobem na zrobienie tego, jeśli chcesz dołączyć kod, jest użycie document.createElementmetody, a następnie użycie .innerHTMLzamiast .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
źródło
0

Próbowałem to jeden i działa dobrze. Po prostu zamień na to <symbol \x3C.

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

lub

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

Możesz przetestować kod tutaj .

Andrzej
źródło
0

Możesz spróbować w ten sposób

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

Jedynym powodem, dla którego nie możesz tego zrobić, "<script></script>"jest to, że ciąg znaków nie jest dozwolony w javascript, ponieważ warstwa DOM nie może przeanalizować, co to jest js, a co HTML.

VipinKundal
źródło
0

Napisałem npmpakiet, który pozwala pobrać ciąg HTML, w tym znaczniki skryptu i dołączyć go do kontenera podczas wykonywania skryptów

Przykład:

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)

Znajdź tutaj: https://www.npmjs.com/package/appendhtml

Lukas
źródło
-1

Wystarczy utworzyć element, analizując go za pomocą jQuery.

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

Przykład roboczy: https://plnkr.co/edit/V2FE28Q2eBrJoJ6PUEBz

sanbor
źródło
Nadal występuje ten sam problem, niektóre przeglądarki tego nie szanują.
Martin Massera
Czy możesz dać mi znać, jakich przeglądarek i jakiej wersji jQuery używasz? Dzięki!
sanbor