无法附加<script>元素

Dan*_*rzo 272 javascript jquery

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

var code = "<script></script>";
$("#someElement").append(code);
Run Code Online (Sandbox Code Playgroud)

Hen*_*zia 349

好消息是:

这是100%的工作.

只需在脚本标记内添加一些内容,例如alert('voila!');.你也许想问一个正确的问题,"为什么我没有在DOM中看到它?" .

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

所有jQuery的插入方法都在内部使用domManip函数来清理/处理元素插入DOM之前和之后.domManip函数所做的一件事就是拉出要插入的任何脚本元素,并通过"evalScript例程"运行它们,而不是将它们注入其余的DOM片段.它单独插入脚本,对它们进行评估,然后将它们从DOM中删除.

我相信jQuery这样做的原因之一是避免在某些情况下插入脚本时Internet Explorer中可能出现的"Permission Denied"错误.如果它位于您正在插入的包含元素内,然后在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);
Run Code Online (Sandbox Code Playgroud)

在那里,就像过去不是它.并且不要忘记在DOM中或在内存中清理所有被引用但不再需要的对象以防止内存泄漏.您可以考虑使用此代码进行清理:

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

这种解决方法的缺点是您可能会意外添加重复的脚本,这很糟糕.从这里开始,您可以.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;
}
Run Code Online (Sandbox Code Playgroud)

这样,您可以添加具有调试功能的脚本,同时避免脚本双重性.这只是一个原型,您可以根据自己的需要进行扩展.我一直在使用这种方法并对此非常满意.果然我永远不会使用jQuery .append()来添加脚本.

  • `$ .getScript`内置于jQuery中. (7认同)
  • 很好的解释,谢谢!但那是"UnusedReferencedObjects"吗? (2认同)

acr*_*man 258

我已经看到一些问题,一些浏览器在你直接执行这些更改时不尊重某些更改(我的意思是通过文本创建HTML,就像你尝试使用脚本标记一样),但是当你使用内置命令执行它们时事情变得更好.试试这个:

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

来自:JSON for jQuery

  • [设置`script.type`是不必要的.](http://mathiasbynens.be/notes/async-analytics-snippet#type) (37认同)
  • <script>标记需要添加到DOM本身,而不是添加到现有元素的innerHTML. (18认同)
  • `$("#someElement")[0] .appendChild(script);` (8认同)
  • @Diodeus innerHTML是DOM的一部分,它由浏览器动态解析,因此这是一个有效的案例. (6认同)
  • 如果你真的希望元素出现在DOM中,不要只使用jQuery的追加.使用本机appendChild来实现此目的. (4认同)

小智 23

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

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

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

  • 这不会在DOM中插入任何内容.它调用`eval()`. (7认同)

Jam*_*mes 20

你的意思是"不工作"?

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

$('#someElement').append('<script>alert("WORKING");</script>');
Run Code Online (Sandbox Code Playgroud)

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


Dar*_*win 17

这有效:

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

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

  • 这是我的唯一解决方案.上面的其他解决方案依赖于html文件中提前存在的javascript代码.由于我是动态添加代码,因此无法提前知道此类javascript代码!感谢达文! (2认同)
  • 或者`var code ="<script> alert('嗨!'); <\/script>";` (2认同)

小智 14

试试这可能会有所帮助:

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

  • 不知道为什么这个家伙否定他是唯一一个不傻到足以继续使用jquery的人! (9认同)