ไม่สามารถผนวก <script> องค์ประกอบ


276

ความคิดใดที่ว่าทำไมโค้ดส่วนล่างไม่เพิ่มองค์ประกอบสคริปต์ลงใน DOM

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

4
กำหนด "ไม่ทำงาน" - แม้ว่าฉันสงสัยว่าปัญหาคือสคริปต์ไม่ได้เป็นส่วนหนึ่งของแผนผัง dom จริงๆ
Joel Coehoorn

1
การเดิมพันของฉันคือการเพิ่มโหนดสคริปต์ใน DOM แต่เบราว์เซอร์ไม่ทำงานสคริปต์
Outlaw Programmer

แดนคุณมีวิธีทดสอบสิ่งนี้อย่างไร
James

1
@Joel - "ไม่ทำงาน" = มันไม่มีผลใด ๆ เช่นรหัสภายในสคริปต์ไม่ได้ถูกดำเนินการ @Outlaw โปรแกรมเมอร์ - โหนดไม่ได้ถูกเพิ่มใน DOM @Jimmy ใช่ฉันได้ทำการทดสอบแล้วและมันไม่ทำงาน
Dan Burzo

คำตอบ:


259

ฉันเคยเห็นปัญหาที่บางเบราว์เซอร์ไม่เคารพการเปลี่ยนแปลงบางอย่างเมื่อคุณทำโดยตรง (ซึ่งฉันหมายถึงการสร้าง HTML จากข้อความเช่นคุณกำลังพยายามแท็กสคริปต์) แต่เมื่อคุณทำด้วยคำสั่งในตัว สิ่งต่าง ๆ ดีขึ้น ลองสิ่งนี้:

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

จาก: JSON สำหรับ jQuery


18
ต้องเพิ่มแท็ก <script> ใน DOM เองไม่ใช่ไปยัง innerHTML ขององค์ประกอบที่มีอยู่
Diodeus - James MacFarlane

6
@Diodeus theHTMLML เป็นส่วนหนึ่งของ DOM และแยกวิเคราะห์ได้ทันทีโดยเบราว์เซอร์ดังนั้นนี่เป็นกรณีที่ถูกต้อง
Cristian Toma


5
อย่าใช้ส่วนต่อท้ายของ jQuery หากคุณต้องการให้องค์ประกอบปรากฏใน DOM ใช้ appendChild ดั้งเดิมเพื่อให้ได้สิ่งนี้
Minqi Pan

8
$("#someElement")[0].appendChild( script );
Minqi Pan

352

ข่าวดีคือ:

มันใช้งานได้ 100%

alert('voila!');เพียงแค่เพิ่มสิ่งที่อยู่ภายในแท็กสคริปต์เช่น คำถามที่ถูกที่คุณอาจต้องการถามบางที"ทำไมฉันไม่เห็นมันใน DOM".

คาร์ล Swedberg ได้ทำคำอธิบายที่ดีที่จะแสดงความคิดเห็นของผู้เข้าชมในเว็บไซต์ jQuery API ฉันไม่ต้องการที่จะทำซ้ำทุกคำพูดของเขาที่คุณสามารถอ่านได้โดยตรงมีที่นี่(ผมพบว่ามันยากที่จะนำทางผ่านความเห็นที่นั่น)

วิธีการแทรกของ jQuery ทั้งหมดใช้ฟังก์ชัน domManip ภายในเพื่อล้าง / ประมวลผลองค์ประกอบก่อนและหลังถูกแทรกลงใน DOM หนึ่งในสิ่งที่ฟังก์ชั่น domManip ทำคือการดึงองค์ประกอบสคริปต์ใด ๆ ที่จะถูกแทรกและเรียกใช้ผ่าน "รูทีน evalScript" แทนที่จะฉีดพวกมันด้วยส่วนที่เหลือของ DOM โดยจะแทรกสคริปต์แยกกันประเมินผลจากนั้นลบสคริปต์ออกจาก DOM

ฉันเชื่อว่าหนึ่งในเหตุผลที่ jQuery ทำเพื่อหลีกเลี่ยงข้อผิดพลาด "สิทธิ์ที่อนุญาต" ที่อาจเกิดขึ้นใน Internet Explorer เมื่อแทรกสคริปต์ในบางกรณี นอกจากนี้ยังหลีกเลี่ยงการแทรก / ประเมินสคริปต์เดียวกันซ้ำ ๆ (ซึ่งอาจทำให้เกิดปัญหา) หากอยู่ในองค์ประกอบที่มีที่คุณกำลังแทรกแล้วย้ายไปรอบ ๆ DOM

สิ่งต่อไปคือฉันจะสรุปสิ่งที่เป็นข่าวร้ายโดยใช้.append()ฟังก์ชั่นเพื่อเพิ่มสคริปต์


และข่าวร้ายก็คือ ..

คุณไม่สามารถดีบักรหัสของคุณได้

ฉันไม่ได้ล้อเล่นแม้ว่าคุณจะเพิ่มdebugger;คำหลักระหว่างบรรทัดที่คุณต้องการตั้งเป็นเบรกพอยต์คุณจะได้รับการโทรสแต็คของวัตถุเท่านั้นโดยไม่เห็นจุดพักบนซอร์สโค้ด(ไม่ต้องพูดถึงว่านี่ คำหลักใช้งานได้ในเบราว์เซอร์ webkit เท่านั้นเบราว์เซอร์หลักอื่น ๆ ทั้งหมดดูเหมือนจะไม่ใช้คำหลักนี้)ที่สำคัญทุกอย่างดูเหมือนจะละเว้นคำหลักนี้)

หากคุณเข้าใจอย่างถ่องแท้ว่าโค้ดของคุณทำอะไรไปกว่านี้จะเป็นอุปสรรคเล็กน้อย แต่ถ้าคุณทำไม่ได้คุณจะต้องเพิ่มdebugger;คำหลักให้ทั่วเพื่อหาว่ามีอะไรผิดปกติกับรหัส (หรือของฉัน) ของคุณ อย่างไรก็ตามมีทางเลือกอื่นอย่าลืมว่าจาวาสคริปต์สามารถจัดการ HTML DOM ได้


วิธีแก้ปัญหา

ใช้ javascript (ไม่ใช่ jQuery) เพื่อจัดการ HTML DOM

หากคุณไม่ต้องการสูญเสียความสามารถในการดีบักคุณสามารถใช้ javascript เนทีฟ HTML DOM เนทิฟ ลองพิจารณาตัวอย่างนี้:

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

มันเป็นเช่นเดียวกับวันเก่าไม่ได้ และอย่าลืมล้างสิ่งต่าง ๆ ไม่ว่าใน DOM หรือในหน่วยความจำสำหรับวัตถุทั้งหมดที่ถูกอ้างถึงและไม่ต้องการอีกต่อไปเพื่อป้องกันการรั่วไหลของหน่วยความจำ คุณสามารถพิจารณารหัสนี้เพื่อทำความสะอาด:

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

ข้อเสียของวิธีแก้ปัญหานี้คือคุณอาจเพิ่มสคริปต์ที่ซ้ำกันโดยไม่ตั้งใจและนั่นก็ไม่ดี จากที่นี่คุณสามารถเลียนแบบ.append()ฟังก์ชันได้เล็กน้อยโดยเพิ่มการตรวจสอบวัตถุก่อนเพิ่มและลบสคริปต์ออกจาก DOM ทันทีหลังจากที่เพิ่ม ลองพิจารณาตัวอย่างนี้:

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

วิธีนี้คุณสามารถเพิ่มสคริปต์ด้วยความสามารถในการดีบักในขณะที่ปลอดภัยจากการทำสำเนาสคริปต์ นี่เป็นเพียงต้นแบบคุณสามารถขยายสิ่งที่คุณต้องการให้เป็น ฉันใช้วิธีนี้และค่อนข้างพอใจกับสิ่งนี้ แน่นอนว่าฉันจะไม่ใช้ jQuery .append()เพื่อเพิ่มสคริปต์


2
คำอธิบายที่ดีขอบคุณ! แต่เป็น "UnusedReferencedObjects" หรือไม่
acme

ขอบคุณ ฉันคิดว่าคุณหมายถึงการเกิดขึ้นครั้งแรกของ "UnusedReferencedObjects" ที่ควรจะเป็นวัตถุใด ๆ ที่คุณสร้างขึ้นในสคริปต์ที่คุณโหลด ฉันเดาว่าคุณเข้าใจดีขึ้นถ้าคุณเห็นว่าฟังก์ชัน DeleteObject ทำอะไรมันแค่ลบวัตถุใด ๆ ที่คุณส่งผ่านไปยังฟังก์ชั่น ฉันจะเพิ่มความคิดเห็นในรหัสเพื่อให้ชัดเจน :)
Hendra Uzia

โพสต์สุดยอด! ตัวอย่างของ aCrosman ไม่ได้ผลสำหรับฉันและหลังจากที่โพสต์ของคุณพร้อมฉันแทนที่ $ ("# someElement") ผนวก (script); กับ $ ("# someElement") [0] .appendChild (สคริปต์); ซึ่งแก้ไขมัน :) ขอบคุณสำหรับการสำรวจ
Maarten Kieft

7
$.getScriptสร้างขึ้นใน jQuery
zzzzBov

SourceURLs ( blog.getfirebug.com/2009/08/11/… ) อาจช่วยแก้ไขปัญหาการดีบัก
vsevik

23

เป็นไปได้ที่จะโหลดไฟล์ JavaScript แบบไดนามิกโดยใช้ฟังก์ชั่น jQuerygetScript

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

ตอนนี้สคริปต์ภายนอกจะถูกเรียกใช้และหากไม่สามารถโหลดได้สคริปต์จะลดระดับลงอย่างงดงาม


7
สิ่งนี้ไม่ได้แทรกอะไรลงใน DOM มันเรียกeval()ว่า
nh2

20

คุณหมายถึง "ไม่ทำงาน"?

jQuery ตรวจพบว่าคุณกำลังพยายามสร้างองค์ประกอบ SCRIPT และจะเรียกใช้เนื้อหาขององค์ประกอบภายในบริบทส่วนกลางโดยอัตโนมัติ คุณกำลังบอกฉันว่าสิ่งนี้ไม่ได้ผลสำหรับคุณ -

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

แก้ไข: หากคุณไม่เห็นองค์ประกอบ SCRIPT ใน DOM (ใน Firebug เป็นต้น) หลังจากที่คุณเรียกใช้คำสั่งที่เป็นเพราะ jQuery อย่างที่ฉันพูดจะเรียกใช้รหัสแล้วจะลบองค์ประกอบ SCRIPT - ฉันเชื่อว่าองค์ประกอบ SCRIPT ถูกผนวกเข้ากับเนื้อความเสมอ ... แต่อย่างไรก็ตาม - การจัดวางไม่มีผลต่อการเรียกใช้โค้ดในสถานการณ์นี้อย่างแน่นอน


17

งานนี้:

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

ดูเหมือนว่า jQuery กำลังทำสิ่งที่ฉลาดกับสคริปต์ดังนั้นคุณต้องผนวกองค์ประกอบ html แทนวัตถุ jQuery


2
นี่เป็นทางออกเดียวที่ทำงานในกรณีของฉัน โซลอื่น ๆ ด้านบนขึ้นอยู่กับรหัสจาวาสคริปต์ที่มีอยู่ก่อนเวลาในไฟล์ html เนื่องจากฉันกำลังเพิ่มรหัสแบบไดนามิกจึงไม่สามารถรู้รหัส javascript ล่วงหน้าได้! ขอบคุณดาร์วิน !!
tgoneil

14

ลองสิ่งนี้อาจเป็นประโยชน์:

var fileref=document.createElement('script');
fileref.setAttribute("type","text/javascript");
fileref.setAttribute("src","scriptAnalytics.js");
document.getElementsByTagName("head")[0].appendChild(fileref);

9
ไม่รู้เลยว่าทำไมชายคนนี้จึงเป็นคนเดียวที่ไม่ฉลาดพอที่จะใช้ jQuery สำหรับทุกสิ่ง!
SSpoke

คำตอบส่วนใหญ่น่าจะใช้ jQuery เพราะในคำถาม OP ใช้ jQuery
sanbor

3

ฉันต้องการทำสิ่งเดียวกัน แต่เพื่อผนวกแท็กสคริปต์ในเฟรมอื่น!

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

3
<script>
    ...
    ...jQuery("<script></script>")...
    ...
</script>

</script>ภายในสตริงสิ้นสุดที่แท้จริงทั้งสคริปต์เพื่อหลีกเลี่ยงการที่"</scr" + "ipt>"สามารถนำมาใช้แทน


หรือไม่ฝัง javascript ของคุณโดยตรงภายในเอกสาร HTML ไฟล์สคริปต์ภายนอกไม่มีปัญหานี้
Ian Clelland

"\x3cscript\x3e\x3c/script\x3e"ลำดับหนี: ใน XHTML คุณจะต้องใส่บล็อก CDATA ที่ถูกใส่ความคิดเห็นเท่านั้น
อีไลเกรย์

2
มันค่อนข้าง</ที่ไม่ได้รับอนุญาต ดูstackoverflow.com/questions/236073/…
Gumbo

2

การเพิ่ม sourceURL ในไฟล์สคริปต์ช่วยตามที่กล่าวไว้ในหน้านี้: https://blog.getfirebug.com/2009/08/11/give-your-eval-a-name-with-sourceurl/

  1. ในไฟล์สคริปต์เพิ่มคำสั่งด้วย sourceURL เช่น "// @ sourceURL = foo.js"
  2. โหลดสคริปต์โดยใช้ jQuery $ .getScript () และสคริปต์จะพร้อมใช้งานในแท็บ "แหล่งที่มา" ในเครื่องมือ dev dev ของ Chrome

1

สคริปต์ของคุณกำลังทำงานคุณไม่สามารถใช้งานdocument.writeได้ document.writeใช้การแจ้งเตือนเพื่อทดสอบและหลีกเลี่ยงการใช้ คำสั่งของไฟล์ js ของคุณด้วยdocument.writeจะไม่ถูกดำเนินการและส่วนที่เหลือของฟังก์ชั่นจะถูกดำเนินการ


1

นี่คือสิ่งที่ฉันคิดว่าเป็นทางออกที่ดีที่สุด Google Analytics ถูกฉีดด้วยวิธีนี้

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

1

คุณไม่จำเป็นต้อง jQuery เพื่อสร้างสคริปต์องค์ประกอบ DOM มันสามารถทำได้กับวานิลลา ES6 เช่น:

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

ไม่จำเป็นต้องห่อในPromiseแต่การทำเช่นนั้นจะช่วยให้คุณสามารถแก้ไขสัญญาเมื่อสคริปต์โหลดขึ้นช่วยป้องกันสภาวะการแข่งขันสำหรับสคริปต์ที่รันนาน


0

ผนวกสคริปต์เข้ากับเนื้อหา:

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

0

วิธีการที่คุณสามารถทำมันได้ถ้าคุณต้องการรหัสต่อท้ายก็คือการใช้document.createElementวิธีการ แต่แล้วใช้แทน.innerHTML.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 );

0

ฉันพยายามนี้อย่างใดอย่างหนึ่งและผลงานที่ดี เพียงแค่แทนที่<สัญลักษณ์ด้วยสิ่ง\x3Cนั้น

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

หรือ

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

คุณสามารถทดสอบรหัสที่นี่


0

ลองแบบนี้

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

เหตุผลเดียวที่คุณไม่สามารถทำได้"<script></script>"คือไม่อนุญาตให้ใช้สตริงใน javascript เพราะเลเยอร์ DOM ไม่สามารถแยกว่า js คืออะไรและ HTML คืออะไร


0

ฉันเขียนnpmแพคเกจที่ช่วยให้คุณใช้สตริง HTML รวมถึงแท็กสคริปต์และผนวกเข้ากับคอนเทนเนอร์ในขณะดำเนินการสคริปต์

ตัวอย่าง:

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)

ค้นหาได้ที่นี่: https://www.npmjs.com/package/appendhtml


-1

เพียงสร้างองค์ประกอบโดยแยกวิเคราะห์ด้วย jQuery

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

ตัวอย่างการทำงาน: https://plnkr.co/edit/V2FE28Q2eBrJoJ6PUEBz


สิ่งนี้ยังคงมีปัญหาเดียวกันเบราว์เซอร์บางตัวไม่เคารพสิ่งนี้
Martin Massera

คุณช่วยบอกให้ฉันรู้ว่าเบราว์เซอร์ใดและคุณใช้ jQuery เวอร์ชันใดอยู่ ขอบคุณ!
sanbor
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.