Không thể nối phần tử <script>


276

Bất cứ ý tưởng tại sao đoạn mã dưới đây không thêm phần tử script vào DOM?

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

4
định nghĩa "không hoạt động" - mặc dù tôi nghi ngờ vấn đề là các tập lệnh không thực sự là một phần của cây dom.
Joel Coehoorn

1
Tôi cá là nút tập lệnh đang được thêm vào DOM, nhưng trình duyệt không thực thi tập lệnh.
Lập trình viên ngoài vòng pháp luật

Dan, làm thế nào bạn thực sự đã thử nghiệm điều này?
James

1
@Joel - "không hoạt động" = nó không có tác dụng gì, tức là mã trong tập lệnh không được thực thi @Outlaw Lập trình viên - nút không được thêm vào DOM @Jimmy Có, tôi đã kiểm tra nó và nó không hoạt động
Dan Burzo

Câu trả lời:


259

Tôi đã thấy các vấn đề trong đó một số trình duyệt không tôn trọng một số thay đổi khi bạn thực hiện chúng trực tiếp (ý tôi là tạo HTML từ văn bản như bạn đang thử với thẻ script), nhưng khi bạn thực hiện chúng bằng các lệnh tích hợp mọi thứ tốt hơn Thử cái này:

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

Từ: JSON cho jQuery


18
Thẻ <script> cần được thêm vào chính DOM, chứ không phải vào bên trongHTML của một phần tử hiện có.
Diodeus - James MacFarlane

6
@Diodeus InternalHTML là một phần của DOM và nó được phân tích cú pháp nhanh chóng bởi trình duyệt, vì vậy đây là trường hợp hợp lệ.
Cristian Toma


5
Đừng chỉ sử dụng phần bổ sung của jQuery nếu bạn thực sự muốn phần tử xuất hiện trong DOM. Sử dụng appendChild bản địa để đạt được điều này.
Minqi Pan

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

352

Tin tốt là:

Nó hoạt động 100%.

Chỉ cần thêm một cái gì đó bên trong thẻ script như alert('voila!');. Câu hỏi đúng mà bạn có thể muốn hỏi có lẽ là "Tại sao tôi không thấy nó trong DOM?" .

Karl Swedberg đã đưa ra một lời giải thích hay cho nhận xét của khách truy cập trong trang web API jQuery . Tôi không muốn lặp lại tất cả các từ của anh ấy, bạn có thể đọc trực tiếp đây (tôi thấy thật khó để điều hướng qua các bình luận ở đó) .

Tất cả các phương thức chèn của jQuery đều sử dụng hàm domManip bên trong để dọn dẹp / xử lý các phần tử trước và sau khi chúng được chèn vào DOM. Một trong những điều mà hàm domManip thực hiện là lấy ra bất kỳ phần tử script nào sắp được chèn và chạy chúng thông qua một "thói quen evalScript" thay vì tiêm chúng vào phần còn lại của đoạn DOM. Nó chèn các tập lệnh riêng biệt, đánh giá chúng và sau đó xóa chúng khỏi DOM.

Tôi tin rằng một trong những lý do jQuery thực hiện điều này là để tránh các lỗi "Quyền bị từ chối" có thể xảy ra trong Internet Explorer khi chèn các tập lệnh trong một số trường hợp nhất định. Nó cũng tránh việc liên tục chèn / đánh giá cùng một tập lệnh (có thể có khả năng gây ra sự cố) nếu nó nằm trong phần tử chứa mà bạn đang chèn và sau đó di chuyển xung quanh DOM.

Điều tiếp theo là, tôi sẽ tóm tắt những tin tức xấu bằng cách sử dụng .append()chức năng để thêm một tập lệnh.


Và Tin xấu là ..

Bạn không thể gỡ lỗi mã của bạn.

Tôi không nói đùa, ngay cả khi bạn thêm debugger;từ khóa giữa dòng bạn muốn đặt làm điểm dừng, cuối cùng bạn sẽ chỉ nhận được ngăn xếp cuộc gọi của đối tượng mà không thấy điểm dừng trên mã nguồn, (không đề cập đến điều này từ khóa chỉ hoạt động trong trình duyệt webkit, tất cả các trình duyệt chính khác dường như bỏ qua từ khóa này) .

Nếu bạn hoàn toàn hiểu mã của bạn làm gì, thì đây sẽ là một nhược điểm nhỏ. Nhưng nếu bạn không, cuối cùng bạn sẽ thêm một debugger;từ khóa ở khắp mọi nơi chỉ để tìm hiểu những gì sai với mã của bạn (hoặc của tôi). Dù sao, có một cách khác, đừng quên rằng javascript có thể thao túng HTML DOM.


Cách giải quyết.

Sử dụng javascript (không phải jQuery) để thao tác HTML DOM

Nếu bạn không muốn mất khả năng sửa lỗi, bạn có thể sử dụng thao tác DOM DOM gốc của javascript. Xem xét ví dụ này:

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

Nó đây rồi, giống như ngày xưa phải không. Và đừng quên dọn dẹp mọi thứ cho dù trong DOM hoặc trong bộ nhớ cho tất cả các đối tượng được tham chiếu và không cần thiết nữa để tránh rò rỉ bộ nhớ. Bạn có thể xem xét mã này để dọn dẹp mọi thứ:

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

Hạn chế từ cách giải quyết này là bạn có thể vô tình thêm một tập lệnh trùng lặp và điều đó thật tệ. Từ đây, bạn có thể bắt chước một chút .append()chức năng bằng cách thêm xác minh đối tượng trước khi thêm và xóa tập lệnh khỏi DOM ngay sau khi được thêm. Xem xét ví dụ này:

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

Bằng cách này, bạn có thể thêm tập lệnh với khả năng sửa lỗi trong khi an toàn khỏi sự trùng lặp tập lệnh. Đây chỉ là một nguyên mẫu, bạn có thể mở rộng cho bất cứ điều gì bạn muốn. Tôi đã và đang sử dụng phương pháp này và khá hài lòng với điều này. Chắc chắn tôi sẽ không bao giờ sử dụng jQuery .append()để thêm một tập lệnh.


2
Giải thích tuyệt vời, cảm ơn! Nhưng là "Un usedReferencedObjects"?
acme

Cảm ơn. Tôi đoán rằng bạn đã đề cập đến lần xuất hiện đầu tiên của "Un usedReferencedObjects", đó được coi là bất kỳ đối tượng nào bạn đã tạo trong tập lệnh bạn tải. Tôi đoán bạn hiểu rõ hơn nếu bạn thấy chức năng DeleteObject làm gì, nó chỉ đơn giản là xóa bất kỳ đối tượng nào bạn chuyển đến hàm. Tôi sẽ thêm một số nhận xét trong mã để rõ ràng. :)
Hendra Uzia

Siêu bài! Ví dụ về aCrosman không hoạt động với tôi và sau khi sẵn sàng bài đăng của bạn, tôi đã thay thế $ ("# someEuity"). Append (script); với $ ("# someEuity") [0] .appendChild (script); Mà đã sửa nó :) Thnx cho cuộc thám hiểm
Maarten Kieft

7
$.getScriptđược tích hợp vào jQuery.
zzzzBov

SourceURLs ( blog.getfireorms.com/2009/08/11/ Khăn ) có thể giúp khắc phục các sự cố.
vsevik

23

Có thể tải động một tệp JavaScript bằng hàm jQuerygetScript

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

Bây giờ tập lệnh bên ngoài sẽ được gọi, và nếu nó không thể được tải, nó sẽ xuống cấp một cách duyên dáng.


7
Điều này không chèn bất cứ điều gì vào DOM. Nó gọi eval().
nh2

20

Bạn có nghĩa là "không làm việc" là gì?

jQuery phát hiện ra rằng bạn đang cố gắng tạo một phần tử SCRIPT và sẽ tự động chạy các nội dung của phần tử trong bối cảnh toàn cầu. Bạn đang nói với tôi rằng điều này không làm việc cho bạn? -

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

Chỉnh sửa: Nếu bạn không thấy phần tử SCRIPT trong DOM (ví dụ trong Fireorms) sau khi bạn chạy lệnh đó vì jQuery, như tôi đã nói, sẽ chạy mã và sau đó sẽ xóa phần tử SCRIPT - Tôi tin rằng các phần tử SCRIPT luôn được gắn vào cơ thể ... nhưng dù sao đi nữa - vị trí hoàn toàn không ảnh hưởng đến việc thực thi mã trong tình huống này.


17

Những công việc này:

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

Có vẻ như jQuery đang làm điều gì đó thông minh với các tập lệnh, do đó bạn cần nối thêm phần tử html chứ không phải đối tượng jQuery.


2
Đây là giải pháp duy nhất hoạt động trong trường hợp của tôi. Các giải pháp khác ở trên phụ thuộc vào mã javascript có trước thời hạn trong tệp html. Vì tôi đang thêm mã động, mã javascript như vậy không thể biết trước được! CẢM ƠN Darwin !!
tgoneil

14

Hãy thử điều này có thể hữu ích:

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

9
không biết tại sao anh chàng này lại phủ nhận người duy nhất không đủ ngu ngốc để tiếp tục sử dụng jquery cho mọi thứ!
SSpoke

Có lẽ hầu hết các câu trả lời đều sử dụng jQuery vì trong câu hỏi OP đang sử dụng jQuery.
sanbor

3

Tôi muốn làm điều tương tự nhưng để thêm một thẻ script trong khung khác!

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>

Trong </script>chuỗi ký tự bằng chữ kết thúc toàn bộ tập lệnh, để tránh điều đó "</scr" + "ipt>"có thể được sử dụng thay thế.


Hoặc không nhúng javascript của bạn trực tiếp trong tài liệu HTML. Các tập lệnh bên ngoài không có vấn đề này.
Ian Clelland

Trình tự thoát : "\x3cscript\x3e\x3c/script\x3e". Trong XHTML, bạn chỉ cần đặt một khối CDATA nhận xét.
Eli Gray

2
Nó đúng hơn </là không được phép. Xem stackoverflow.com/questions/236073/
Mạnh


1

Kịch bản của bạn đang thực thi, bạn không thể sử dụng document.writenó. Sử dụng một cảnh báo để kiểm tra nó và tránh sử dụng document.write. Các câu lệnh của tệp js của bạn document.writesẽ không được thực thi và phần còn lại của hàm sẽ được thực thi.


1

Đây là những gì tôi nghĩ là giải pháp tốt nhất. Google Analytics được tiêm theo cách này.

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

Bạn không cần jQuery để tạo Phần tử DOM Script . Nó có thể được thực hiện với vanilla ES6 như vậy:

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

Không cần phải gói gọn trong một Promise, nhưng làm như vậy cho phép bạn giải quyết lời hứa khi tập lệnh tải, giúp ngăn chặn điều kiện chạy đua cho các tập lệnh chạy dài.


0

Nối tập lệnh vào phần thân:

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

0

Một cách khác bạn có thể làm nếu bạn muốn nối thêm mã là sử dụng document.createElementphương thức nhưng sau đó sử dụng .innerHTMLthay vì .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

Tôi cố gắng này một và các công trình tốt. Chỉ cần thay thế <biểu tượng với điều đó \x3C.

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

hoặc là

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

Bạn có thể kiểm tra mã ở đây .


0

Có thể thử như thế này

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

Lý do duy nhất bạn không thể làm "<script></script>"là vì chuỗi không được phép trong javascript vì lớp DOM không thể phân tích được js và HTML là gì.


0

Tôi đã viết một npmgói cho phép bạn lấy một chuỗi HTML, bao gồm các thẻ script và nối nó vào một container trong khi thực thi các script

Thí dụ:

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)

Tìm nó ở đây: https://www.npmjs.com/package/appendhtml


-1

Chỉ cần tạo một phần tử bằng cách phân tích cú pháp bằng jQuery.

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

Ví dụ hoạt động: https://plnkr.co/edit/V2FE28Q2eBrJoJ6PUEBz


Điều này vẫn có cùng một vấn đề, một số trình duyệt không tôn trọng điều này.
Martin Massera

Bạn có thể vui lòng cho tôi biết trình duyệt nào và phiên bản jQuery nào bạn đang sử dụng không? Cảm ơn!
sanbor
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.