Tidak dapat menambahkan elemen <script>

276

Adakah gagasan mengapa potongan kode di bawah ini tidak menambahkan elemen skrip ke DOM?

var code = "<script></script>";
$("#someElement").append(code);
Dan Burzo
sumber
4
mendefinisikan "tidak berfungsi" - meskipun saya menduga masalahnya adalah bahwa skrip tidak benar-benar bagian dari pohon dom.
Joel Coehoorn
1
Taruhan saya adalah bahwa node script sedang ditambahkan ke DOM, tetapi browser tidak menjalankan script.
Outlaw Programmer
Dan, bagaimana Anda benar-benar menguji ini?
James
1
@ Joel - "tidak berfungsi" = tidak ada efek apa pun, yaitu kode dalam skrip tidak dieksekusi @Outlaw Programmer - node tidak ditambahkan ke DOM @ Jimim Ya, saya telah mengujinya dan itu tidak berfungsi
Dan Burzo

Jawaban:

259

Saya telah melihat masalah di mana beberapa browser tidak menghargai beberapa perubahan ketika Anda melakukannya secara langsung (maksud saya membuat HTML dari teks seperti Anda mencoba dengan tag skrip), tetapi ketika Anda melakukannya dengan perintah bawaan segalanya menjadi lebih baik. Coba ini:

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

Dari: JSON untuk jQuery

pelakon
sumber
18
Tag <script> perlu ditambahkan ke DOM itu sendiri, bukan ke innerHTML elemen yang ada.
Diodeus - James MacFarlane
6
@Diodeus, innerHTML adalah bagian dari DOM dan diuraikan dengan cepat oleh browser, jadi ini adalah kasus yang valid.
Cristian Toma
5
Jangan hanya menggunakan append jQuery jika Anda benar-benar ingin elemen tersebut muncul di DOM. Gunakan appendChild asli untuk mencapai ini.
Minqi Pan
8
$("#someElement")[0].appendChild( script );
Minqi Pan
352

Kabar Baik adalah:

Ini 100% berfungsi.

Cukup tambahkan sesuatu di dalam tag skrip seperti alert('voila!');. Pertanyaan yang tepat yang mungkin ingin Anda tanyakan, "Mengapa saya tidak melihatnya di DOM?" .

Karl Swedberg telah membuat penjelasan yang bagus untuk komentar pengunjung di situs API jQuery . Saya tidak ingin mengulangi semua kata-katanya, Anda dapat membaca langsung di sana di sini (saya merasa sulit untuk menavigasi melalui komentar di sana) .

Semua metode penyisipan jQuery menggunakan fungsi domManip secara internal untuk membersihkan / memproses elemen sebelum dan sesudah mereka dimasukkan ke dalam DOM. Salah satu hal yang dilakukan fungsi domManip adalah mengeluarkan elemen skrip yang akan dimasukkan dan menjalankannya melalui "evalScript rutin" daripada menyuntikkan mereka dengan sisa fragmen DOM. Itu menyisipkan skrip secara terpisah, mengevaluasinya, dan kemudian menghapusnya dari DOM.

Saya percaya bahwa salah satu alasan jQuery melakukan ini adalah untuk menghindari kesalahan "Izin ditolak" yang dapat terjadi di Internet Explorer saat memasukkan skrip dalam keadaan tertentu. Itu juga menghindari berulang kali memasukkan / mengevaluasi skrip yang sama (yang berpotensi menyebabkan masalah) jika berada dalam elemen yang mengandung yang Anda sisipkan dan kemudian bergerak di sekitar DOM.

Hal berikutnya adalah, saya akan meringkas apa kabar buruk dengan menggunakan .append()fungsi untuk menambahkan skrip.


Dan Berita Buruknya adalah ..

Anda tidak dapat men-debug kode Anda.

Saya tidak bercanda, bahkan jika Anda menambahkan debugger;kata kunci di antara baris yang ingin Anda tetapkan sebagai breakpoint, Anda hanya akan mendapatkan tumpukan panggilan objek tanpa melihat breakpoint pada kode sumber, (belum lagi bahwa ini kata kunci hanya berfungsi di peramban webkit, semua peramban utama lainnya sepertinya mengabaikan kata kunci ini) .

Jika Anda sepenuhnya memahami apa yang kode Anda lakukan, maka ini akan menjadi kelemahan kecil. Tetapi jika tidak, Anda akhirnya akan menambahkan debugger;kata kunci di semua tempat hanya untuk mengetahui apa yang salah dengan kode Anda (atau saya). Lagi pula, ada alternatif, jangan lupa bahwa javascript dapat memanipulasi HTML DOM secara asli.


Penanganan masalah.

Gunakan javascript (bukan jQuery) untuk memanipulasi HTML DOM

Jika Anda tidak ingin kehilangan kemampuan debug, Anda dapat menggunakan manipulasi DOM HTML asli javascript. Pertimbangkan contoh ini:

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

Itu dia, sama seperti masa lalu bukan. Dan jangan lupa untuk membersihkan semuanya baik di DOM atau di memori untuk semua objek yang direferensikan dan tidak diperlukan lagi untuk mencegah kebocoran memori. Anda dapat mempertimbangkan kode ini untuk membersihkan:

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

Kelemahan dari pemecahan masalah ini adalah Anda mungkin secara tidak sengaja menambahkan skrip duplikat, dan itu buruk. Dari sini Anda dapat sedikit meniru .append()fungsi dengan menambahkan verifikasi objek sebelum menambahkan, dan menghapus skrip dari DOM tepat setelah ditambahkan. Pertimbangkan contoh ini:

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

Dengan cara ini, Anda dapat menambahkan skrip dengan kemampuan debugging sementara aman dari duplikasi skrip. Ini hanya prototipe, Anda dapat memperluas apa pun yang Anda inginkan. Saya telah menggunakan pendekatan ini dan cukup puas dengan ini. Cukup yakin saya tidak akan pernah menggunakan jQuery .append()untuk menambahkan skrip.

Hendra Uzia
sumber
2
Penjelasan yang bagus, terima kasih! Tetapi apakah "UnusedReferencedObjects"?
acme
Terima kasih. Saya kira Anda merujuk pada kemunculan pertama "UnusedReferencedObjects", yang seharusnya merupakan objek yang Anda buat dalam skrip yang Anda muat. Saya kira Anda lebih mengerti jika Anda melihat apa fungsi DeleteObject tidak, itu hanya menghapus objek yang Anda berikan ke fungsi. Saya akan menambahkan beberapa komentar dalam kode agar jelas. :)
Hendra Uzia
Pos super! Contoh aCrosman tidak berfungsi untuk saya dan setelah selesai memposting, saya mengganti $ ("# someElement"). Append (script); dengan $ ("# someElement") [0] .appendChild (skrip); Yang memperbaikinya :) Thnx untuk penjelajahan
Maarten Kieft
7
$.getScriptdibangun ke dalam jQuery.
zzzzBov
SourceURLs ( blog.getfirebug.com/2009/08/11/... ) dapat membantu masalah debugging.
vsevik
23

Dimungkinkan untuk memuat file JavaScript secara dinamis menggunakan fungsi jQuerygetScript

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

Sekarang skrip eksternal akan dipanggil, dan jika tidak dapat dimuat, skrip tersebut akan diturunkan dengan anggun.

Cueball
sumber
7
Ini tidak memasukkan apa pun ke DOM. Itu panggilan eval().
nh2
20

Apa maksudmu "tidak bekerja"?

jQuery mendeteksi bahwa Anda mencoba membuat elemen SCRIPT dan secara otomatis akan menjalankan konten elemen dalam konteks global. Apakah Anda mengatakan kepada saya bahwa ini tidak berhasil untuk Anda? -

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

Sunting: Jika Anda tidak melihat elemen SCRIPT di DOM (di Firebug misalnya) setelah Anda menjalankan perintah itu karena jQuery, seperti yang saya katakan, akan menjalankan kode dan kemudian akan menghapus elemen SCRIPT - Saya percaya bahwa elemen SCRIPT selalu ditambahkan ke badan ... tapi bagaimanapun - penempatan sama sekali tidak ada kaitannya dengan eksekusi kode dalam situasi ini.

James
sumber
17

Ini bekerja:

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

Sepertinya jQuery melakukan sesuatu yang pintar dengan skrip sehingga Anda perlu menambahkan elemen html daripada objek jQuery.

Darwin
sumber
2
Ini adalah satu-satunya solusi yang berfungsi dalam kasus saya. Solusi lain di atas tergantung pada kode javascript yang ada sebelumnya dalam file html. Karena saya menambahkan kode secara dinamis, kode javascript seperti itu tidak dapat diketahui sebelumnya! TERIMA KASIH Darwin !!
tgoneil
14

Coba ini semoga bermanfaat:

var fileref=document.createElement('script');
fileref.setAttribute("type","text/javascript");
fileref.setAttribute("src","scriptAnalytics.js");
document.getElementsByTagName("head")[0].appendChild(fileref);
Jainul Khan
sumber
9
tidak tahu mengapa orang ini negatif karena dia satu-satunya yang tidak cukup bodoh untuk terus menggunakan jquery untuk semuanya!
SSpoke
Mungkin sebagian besar jawaban menggunakan jQuery karena dalam pertanyaan OP menggunakan jQuery.
sanbor
3

Saya ingin melakukan hal yang sama tetapi menambahkan tag skrip di bingkai lain!

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

Dalam </script>string literal mengakhiri seluruh skrip, untuk menghindari hal itu "</scr" + "ipt>"dapat digunakan sebagai gantinya.

Roman Odaisky
sumber
Atau jangan sematkan javascript Anda langsung di dalam dokumen HTML. File skrip eksternal tidak memiliki masalah ini.
Ian Clelland
Escape sequence: "\x3cscript\x3e\x3c/script\x3e". Di XHTML, Anda hanya perlu memasukkan blok CDATA yang sudah dikomentari.
Eli Grey
2
Ini agak </tidak diizinkan. Lihat stackoverflow.com/questions/236073/...
Gumbo
1

Script Anda sedang dieksekusi, Anda tidak bisa menggunakannya document.write. Gunakan lansiran untuk mengujinya dan menghindari penggunaan document.write. Pernyataan file js Anda dengan document.writetidak akan dieksekusi dan sisa fungsi akan dieksekusi.

Kunal Kinalekar
sumber
1

Inilah yang saya pikir merupakan solusi terbaik. Google Analytics disuntikkan dengan cara ini.

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
sumber
1

Anda tidak perlu jQuery untuk membuat Elemen DOM Script . Ini dapat dilakukan dengan vanilla ES6 seperti:

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

Itu tidak perlu dibungkus dengan Promise, tetapi dengan melakukan hal itu Anda dapat menyelesaikan janji ketika skrip dimuat, membantu mencegah kondisi balapan untuk skrip yang sudah berjalan lama.

Josh Habdas
sumber
0

Tambahkan skrip ke badan:

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

Cara lain yang dapat Anda lakukan jika Anda ingin menambahkan kode menggunakan document.createElementmetode tetapi kemudian menggunakan .innerHTMLalih-alih .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
sumber
0

Saya mencoba ini satu dan bekerja dengan baik. Cukup ganti <simbolnya dengan itu \x3C.

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

atau

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

Anda dapat menguji kodenya di sini .

Andrew
sumber
0

Bisa coba seperti ini

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

Satu-satunya alasan Anda tidak dapat melakukannya "<script></script>"adalah karena string tidak diizinkan di dalam javascript karena lapisan DOM tidak dapat menguraikan apa js dan apa itu HTML.

VipinKundal
sumber
0

Saya menulis sebuah npmpaket yang memungkinkan Anda mengambil string HTML, termasuk tag skrip dan menambahkannya ke sebuah wadah saat menjalankan skrip

Contoh:

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)

Temukan di sini: https://www.npmjs.com/package/appendhtml

Lukas
sumber
-1

Cukup buat elemen dengan menguraikannya dengan jQuery.

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

Contoh kerja: https://plnkr.co/edit/V2FE28Q2eBrJoJ6PUEBz

sanbor
sumber
Ini masih memiliki masalah yang sama, beberapa browser tidak menghargai ini.
Martin Massera
Bisakah Anda memberi tahu saya browser apa dan versi jQuery apa yang Anda gunakan? Terima kasih!
sanbor