不能't追加<script>元素

你知道为什么下面这段代码没有将脚本元素添加到DOM中吗?

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

我曾见过一些浏览器在你直接执行某些更改时不尊重它们的问题(我指的是从文本创建HTML,就像你尝试使用script标记一样),但当你使用内置命令执行这些更改时,事情会变得更好。试试这个:

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

来自:JSON for jQuery

你说“不工作”是什么意思?

jQuery检测到您正在尝试创建一个SCRIPT元素,并将自动在全局上下文中运行元素的内容。你是说这对你没用吗?-

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

编辑:如果你在运行命令后没有在DOM中看到SCRIPT元素(例如在Firebug中),这是因为jQuery,就像我说的,将运行代码,然后将删除SCRIPT元素-我相信SCRIPT元素总是附加到主体…但无论如何,在这种情况下,位置对代码执行完全没有影响。

我想做同样的事情,但附加一个脚本标签在其他框架!

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

字符串字面量中的</script>终止了整个脚本,以避免使用"</scr" + "ipt>"代替。

可以使用jQuery函数getScript . xml文件动态加载JavaScript文件

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

现在外部脚本将被调用,如果不能加载它,它将优雅地降级。

如此:

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

jQuery似乎在脚本上做了一些聪明的事情,所以你需要附加html元素而不是jQuery对象。

好消息是:

100%有效。

只需在脚本标记中添加一些东西,例如alert('voila!');。你可能想问的正确问题是“为什么我在DOM中没有看到它?”< / em >

Karl Swedberg在jQuery API站点中对访客的评论做了很好的解释。我想重复他所有的话,你可以直接读在那里在这里。

jQuery的所有插入方法 内部的domManip函数 和之前清洗/处理元素 在它们被插入到DOM之后。 其中一件事是domManip 函数的作用是取出任何脚本 将要插入并运行的元素 他们通过一个“evalScript例程” 而不是把剩下的注射给他们 DOM片段。它插入 分别计算脚本, 然后从DOM中移除它们。

我相信jQuery的原因之一 这是为了避免“允许? 中可能发生的错误 插入ie浏览器时 特定情况下的脚本。 它也避免了重复 插入/计算相同的脚本 (这可能会导致 问题),如果它是在包含 要插入的元素 然后在DOM中移动

下一件事是,我将通过使用.append()函数添加一个脚本来总结坏消息。


坏消息是…

你不能调试代码。

我不是在开玩笑,即使你在你想设置为断点的行之间添加了debugger;关键字,你最终只会得到对象的调用堆栈,而不会在源代码中看到断点(更不用说这个关键字只适用于webkit浏览器,所有其他主要浏览器似乎都省略了这个关键字)

如果您完全理解您的代码是做什么的,那么这将是一个小缺点。但如果你不这样做,你最终会在所有地方添加debugger;关键字,只是为了找出你(或我)的代码有什么问题。不管怎样,还有另一种选择,不要忘记javascript可以原生操作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()来添加脚本。

在脚本文件中添加sourceURL,如本页所述: https://blog.getfirebug.com/2009/08/11/give-your-eval-a-name-with-sourceurl/ < / p >
  1. 在脚本文件中,添加一个带有sourceURL的语句,如"//@ sourceURL=foo.js"
  2. 使用jQuery $.getScript()加载脚本,脚本将在chrome开发工具的“sources”选项卡中可用

你的脚本正在执行,你只是不能从它使用document.write。使用警报来测试它,避免使用document.write。js文件中带有document.write的语句将不被执行,函数的其余部分将被执行。

试试这个可能会有帮助:

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

将脚本追加到正文:

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

这是我认为最好的解决办法。谷歌分析就是这样注入的。

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

如果你想追加代码,另一种方法是使用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 );

只需通过jQuery解析来创建一个元素。

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

工作示例:https://plnkr.co/edit/V2FE28Q2eBrJoJ6PUEBz

你不需要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中,但是这样做可以让你在脚本加载时解析承诺,有助于防止长时间运行的脚本出现竞争条件。

我尝试了这个一个,工作正常。只需将<符号替换为\x3C

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

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

你可以测试代码在这里

可以这样试试

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

你不能做"<script></script>"的唯一原因是因为字符串在javascript中是不允许的,因为DOM层不能解析什么是js,什么是HTML。

我写了一个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