无法追加<script>元素


276

知道为什么下面的代码没有将script元素添加到DOM吗?

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

4
定义“不起作用”-尽管我怀疑问题在于脚本实际上并不是dom树的一部分。
Joel Coehoorn

1
我敢打赌,脚本节点已添加到DOM,但浏览器没有执行脚本。
Outlaw程序员,2009年

丹,您实际如何对此进行测试?
詹姆斯

1
@Joel-“不起作用” =它没有任何作用,即脚本中的代码未执行@Outlaw程序员-节点未添加到DOM @Jimmy是的,我已经对其进行了测试并且不起作用
Dan Burzo 09年

Answers:


259

我见过这样的问题:某些浏览器在您直接进行更改时(例如,您正在尝试使用script标记从文本中创建HTML)却不执行某些更改,而当您使用内置命令进行更改时情况变得更好。试试这个:

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

来自:jQuery的JSON


18
需要将<script>标记添加到DOM本身,而不是添加到现有元素的innerHTML。
Diodeus-James MacFarlane

6
@Diodeus innerHTML是DOM的一部分,它是由浏览器动态解析的,因此这是一个有效的情况。
克里斯蒂安·托玛


5
如果您确实希望元素出现在DOM中,请不要仅使用jQuery的append。使用本机的appendChild可以实现此目的。
潘敏琦2012年

8
$("#someElement")[0].appendChild( script );
潘敏琦2012年

352

好消息是:

100%工作。

只需在script标签内添加一些内容,例如alert('voila!');。您可能想问的正确问题也许是:“为什么我没有在DOM中看到它?”

Karl Swedberg在jQuery API网站上对访问者的评论做了很好的解释。我希望重复自己的一切话,你可以直接读取出现在这里(我发现很难通过导航的评论那里)

jQuery的所有插入方法都在内部使用domManip函数在将元素插入DOM之前和之后清洗/处理元素。domManip函数要做的一件事是提取将要插入的所有脚本元素,并通过“ evalScript例程”运行它们,而不是将它们与DOM片段的其余部分一起注入。它分别插入脚本,对其进行评估,然后将其从DOM中删除。

我相信jQuery这样做的原因之一是为了避免在某些情况下插入脚本时Internet Explorer中可能发生的“权限被拒绝”错误。如果它在要插入的包含元素中,然后在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()添加脚本。


2
很好的解释,谢谢!但是是“ UnusedReferencedObjects”吗?
acme 2010年

谢谢。我假设您是指“ UnusedReferencedObjects”的首次出现,它应该是您在加载的脚本中创建的任何对象。我想您会更好地了解,如果您看到DeleteObject函数的作用,它只会删除传递给该函数的所有对象。我将在代码中添加一些注释以使其清晰。:)
Hendra Uzia 2010年

超级帖子!aCrosman的示例对我不起作用,在准备好您的帖子后,我替换了$(“#someElement”)。append(script); 与$(“#someElement”)[0] .appendChild(script); 修复它的原因:) Thnx进行外植
Maarten Kieft

7
$.getScript内置在jQuery中。
zzzzBov 2012年

SourceURL(blog.getfirebug.com/2009/08/11/…)可能有助于解决调试问题。
vsevik

23

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

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

现在将调用外部脚本,如果无法加载该外部脚本,它将正常降级。


7
这不会在DOM中插入任何内容。它调用eval()
nh2 2013年

20

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

jQuery检测到您正在尝试创建一个SCRIPT元素,并将在全局上下文中自动运行该元素的内容。您是在告诉我这不适合您吗?--

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

编辑:如果您在运行命令后未在DOM中看到SCRIPT元素(例如在Firebug中),那是因为jQuery(如我所说)将运行代码,然后删除SCRIPT元素-我相信SCRIPT元素总是附加到主体上...但是无论如何-在这种情况下,放置绝对不影响代码执行。


17

这有效:

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

似乎jQuery在脚本方面做得很聪明,因此您需要附加html元素而不是jQuery对象。


2
这是唯一适合我的解决方案。上面的其他解决方案取决于html文件中提前提供的javascript代码。由于我是动态添加代码,因此无法提前知道此类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进行所有操作!
S辐

可能大多数答案都使用jQuery,因为在这个问题中OP正在使用jQuery。
桑博尔'17

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文档中。外部脚本文件没有此问题。
伊恩·克莱兰

转义序列:"\x3cscript\x3e\x3c/script\x3e"。在XHTML中,您只需要放入一个注释掉的CDATA块。
伊莱·格雷

2
而是</那是不允许的。参见stackoverflow.com/questions/236073/…–
Gumbo,


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.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>"是,由于DOM层无法解析js和HTML,因此javascript中不允许使用该字符串。


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


这仍然有相同的问题,某些浏览器不尊重这一点。
马丁·马塞拉

您能否让我知道您使用的是哪种浏览器和什么版本的jQuery?谢谢!
桑博尔'17
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.