无法附加 <script> 元素

Posted

技术标签:

【中文标题】无法附加 <script> 元素【英文标题】:Can't append <script> element 【发布时间】:2010-10-11 07:01:22 【问题描述】:

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

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

【问题讨论】:

定义“不工作”——虽然我怀疑问题是脚本并不是 dom 树的一部分。 我敢打赌,脚本节点正在被添加到 DOM,但浏览器并没有执行脚本。 Dan,你是如何实际测试的? @Joel - “不工作” = 它没有任何效果,即脚本中的代码没有执行 @Outlaw Programmer - 节点没有添加到 DOM @Jimmy 是的,我有测试它,它不工作 【参考方案1】:

好消息是:

100% 正常工作。

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

Karl Swedberg 对jQuery API site 中访客的评论做了很好的解释。我不想想重复他的所有话,你可以直接阅读there这里(我发现那里的cmets很难导航) .

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()添加脚本。

【讨论】:

很好的解释,谢谢!但是是“UnusedReferencedObjects”吗? 谢谢。我假设您指的是“UnusedReferencedObjects”的第一次出现,它应该是您在加载的脚本中创建的任何对象。我想如果你看到 DeleteObject 函数做了什么,你会更好地理解,它只是删除你传递给函数的任何对象。为了清楚起见,我将在代码中添加一些注释。 :) 超级帖子! aCrosman 的示例对我不起作用,在准备好您的帖子后,我替换了 $("#someElement").append(script);与 $("#someElement")[0].appendChild(script);哪个修复了它:)谢谢你的解释 $.getScript 内置在 jQuery 中。 SourceURLs (blog.getfirebug.com/2009/08/11/…) 可能有助于解决调试问题。【参考方案2】:

我已经看到一些浏览器在您直接执行某些更改时不尊重某些更改的问题(我的意思是从文本创建 HTML,就像您尝试使用 script 标签一样),但是当您使用 built -in 命令事情变得更好。试试这个:

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

发件人:JSON for jQuery

【讨论】:

@Diodeus innerHTML 是 DOM 的一部分,它由浏览器动态解析,所以这是一个有效的案例。 Setting script.type is unnecessary. 如果你真的希望元素出现在 DOM 中,不要只使用 jQuery 的追加。使用本机 appendChild 来实现这一点。 $("#someElement")[0].appendChild( script );【参考方案3】:

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

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

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

【讨论】:

这不会向 DOM 中插入任何内容。它调用eval()【参考方案4】:

“不工作”是什么意思?

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

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

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

【讨论】:

太棒了!似乎没有原版的等价物,但没有绝望,因为你总是可以just load jQuery first。【参考方案5】:

这行得通:

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

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

【讨论】:

这是唯一适用于我的解决方案。上面的其他解决方案取决于 html 文件中提前存在的 javascript 代码。由于我是动态添加代码的,因此无法提前知道此类 javascript 代码!谢谢达尔文!! James' code 对我来说效果更好。不仅因为它既不需要$()[0],也不需要转义(例如\/script),还因为这里的代码由于某种原因不能处理多个标签(例如,多个脚本),而@James'可以。 【参考方案6】:

试试这个可能会有帮助:

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

【讨论】:

不知道为什么这家伙否定他是唯一一个不傻到继续使用 jquery 做所有事情的人! 可能大多数答案都使用 jQuery,因为在问题中 OP 正在使用 jQuery。【参考方案7】:

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

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

【讨论】:

【参考方案8】:
<script>
    ...
    ...jQuery("<script></script>")...
    ...
</script>

字符串文字中的&lt;/script&gt; 终止整个脚本,以避免可以使用"&lt;/scr" + "ipt&gt;" 代替。

【讨论】:

或者不要将您的 javascript 直接嵌入到 HTML 文档中。外部脚本文件没有这个问题。 转义序列:"\x3cscript\x3e\x3c/script\x3e"。在 XHTML 中,您只需要放入一个注释掉的 CDATA 块。 这是不允许的&lt;/。见***.com/questions/236073/…【参考方案9】:

在脚本文件中添加 sourceURL 有帮助,如本页所述: https://blog.getfirebug.com/2009/08/11/give-your-eval-a-name-with-sourceurl/

    在脚本文件中,添加一条带有 sourceURL 的语句,例如“//@ sourceURL=foo.js” 使用 jQuery $.getScript() 加载脚本,该脚本将在 chrome 开发工具的“源”选项卡中可用

【讨论】:

【参考方案10】:

您的脚本正在执行,您不能从中使用document.write。使用警报对其进行测试并避免使用document.write。你的js文件中document.write的语句不会被执行,其余的函数都会被执行。

【讨论】:

【参考方案11】:

这是我认为最好的解决方案。 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); )();

【讨论】:

【参考方案12】:

您不需要 jQuery 来创建 Script DOM Element。可以使用 vanilla 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 中,但这样做可以让您在脚本加载时解决承诺,有助于防止长时间运行的脚本出现竞争条件。

【讨论】:

【参考方案13】:

将脚本附加到正文:

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

【讨论】:

【参考方案14】:

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

【讨论】:

【参考方案15】:

我试过这个one 并且工作正常。只需将 &lt; 符号替换为 \x3C

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

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

您可以测试代码here。

【讨论】:

【参考方案16】:

可以这样试试

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

您不能执行"&lt;script&gt;&lt;/script&gt;" 的唯一原因是因为 DOM 层无法解析什么是 js 和什么是 HTML,所以在 javascript 中不允许使用该字符串。

【讨论】:

【参考方案17】:

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

【讨论】:

【参考方案18】:

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

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

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

【讨论】:

这个还是一样的问题,有些浏览器不尊重这个。 你能告诉我你使用的是什么浏览器和什么版本的jQuery吗?谢谢!

以上是关于无法附加 <script> 元素的主要内容,如果未能解决你的问题,请参考以下文章

将元素作为兄弟元素附加在元素之后? [复制]

在更改事件中将文本附加到 Summernote 元素时出现问题

为啥将 <script> 附加到动态创建的 <iframe> 似乎会在父页面中运行脚本?

DOMParser 将 <script> 标记附加到 <head>/<body> 但不执行

如何在两个元素之间附加一个元素

在其他元素之后附加一个元素