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);
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);
Câu trả lời:
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
$("#someElement")[0].appendChild( script );
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.
$.getScript
được tích hợp vào jQuery.
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.
eval()
.
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.
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.
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);
<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ế.
"\x3cscript\x3e\x3c/script\x3e"
. Trong XHTML, bạn chỉ cần đặt một khối CDATA nhận xét.
</
là không được phép. Xem stackoverflow.com/questions/236073/
Thêm nguồnURL trong tệp tập lệnh đã giúp như được đề cập trong trang này: https://blog.getfireorms.com/2009/08/11/give-your-eval-a-name-with-sourceurl/
Kịch bản của bạn đang thực thi, bạn không thể sử dụng document.write
nó. 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.write
sẽ không được thực thi và phần còn lại của hàm sẽ được thực thi.
Đâ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); })();
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.
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");
});
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.createElement
phương thức nhưng sau đó sử dụng .innerHTML
thay 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 );
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 .
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ì.
Tôi đã viết một npm
gó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
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