可以用innerHTML 插入脚本吗?

IT技术 javascript html dom innerhtml
2020-12-31 15:58:52

我想一些脚本加载到使用页面innerHTML<div>脚本似乎加载到 DOM 中,但从未执行过(至少在 Firefox 和 Chrome 中)。有没有办法在插入脚本时执行脚本innerHTML

示例代码:

<!DOCTYPE html>
<html>
  <body onload="document.getElementById('loader').innerHTML = '<script>alert(\'hi\')<\/script>'">
    Shouldn't an alert saying 'hi' appear?
    <div id="loader"></div>
  </body>
</html>

6个回答

您必须使用eval()来执行您作为 DOM 文本插入的任何脚本代码。

MooTools 会自动为你做这件事,我相信 jQuery 也会(取决于版本。jQuery 1.6+ 版使用eval)。这样可以省去很多解析<script>标签和转义内容的麻烦,以及一堆其他“问题”。

通常,如果您要eval()自己动手,您希望创建/发送没有任何 HTML 标记(例如 )的脚本代码<script>,因为这些将不eval()正确。

我真正想做的是加载一个外部脚本,而不仅仅是 eval 一些本地脚本。添加带有innerHTML 的脚本标记比创建脚本DOM 元素并将其添加到正文要短得多,而且我试图使我的代码尽可能短。您是否必须创建 dom 脚本元素并将它们添加到 dom 中,而不是仅仅使用诸如 innerHTML 之类的东西?有没有办法在函数内使用 document.write 做到这一点?
2021-02-15 15:58:52
eval() 不是解决任何问题的好方法。
2021-02-18 15:58:52
阿里尔是对的。我很欣赏让你的代码保持简短,并且添加一个<script>标签innerHTML可能很短,但它不起作用。在它运行之前,这一切都只是纯文本eval()遗憾的是,eval()它不解析 HTML 标签,因此您最终会遇到一系列问题。
2021-02-26 15:58:52
我自己试过 eval() 。这是一个可怕的想法。你必须EVAL整个事情每次即使你声明了一个变量名和值,你也必须每次重新声明/重新评估()以使其工作。这是错误的噩梦。
2021-03-02 15:58:52
正如 zombat 建议的那样,使用 Javascript 框架来加载外部脚本,不要尝试重新发明轮子。JQuery 使这变得非常简单,只需包含 JQuery 并调用:$.getScript(url)。您还可以提供一个回调函数,该函数将在脚本加载后执行。
2021-03-07 15:58:52

这是一种递归地将所有脚本替换为可执行脚本的方法:

function nodeScriptReplace(node) {
        if ( nodeScriptIs(node) === true ) {
                node.parentNode.replaceChild( nodeScriptClone(node) , node );
        }
        else {
                var i = -1, children = node.childNodes;
                while ( ++i < children.length ) {
                      nodeScriptReplace( children[i] );
                }
        }

        return node;
}
function nodeScriptClone(node){
        var script  = document.createElement("script");
        script.text = node.innerHTML;

        var i = -1, attrs = node.attributes, attr;
        while ( ++i < attrs.length ) {                                    
              script.setAttribute( (attr = attrs[i]).name, attr.value );
        }
        return script;
}

function nodeScriptIs(node) {
        return node.tagName === 'SCRIPT';
}

示例调用:

nodeScriptReplace(document.getElementsByTagName("body")[0]);
[0] 的目的是什么?你可以使用 nodeScriptReplace(document.getElementById().html);
2021-02-07 15:58:52
这真是太神奇了。完美运行
2021-02-13 15:58:52
很棒的解决方案,谢谢:) 如果有人正在寻找更现代的版本:stackoverflow.com/a/69190644/1343851
2021-02-16 15:58:52
我有点惊讶你的回答一直下降。恕我直言,这是最好的解决方案,这种方法甚至可以让您限制具有特定网址或内容的脚本。
2021-02-20 15:58:52
这太棒了。谢谢你。
2021-02-22 15:58:52

这是您问题的一个非常有趣的解决方案:http : //24ways.org/2005/have-your-dom-and-script-it-too

所以使用它而不是脚本标签:

<img src="empty.gif" onload="alert('test');this.parentNode.removeChild(this);" />

你们如何将 <img src... 行添加到您的页面代码中?您是使用 document.write() 还是使用 document.body.innerHTML+= 方法?两者都不适合我:(
2021-02-17 15:58:52
两个缺点: 1. 它不能调用通过innerHTML(连同这个IMG 标签)添加的任何脚本/函数,因为就浏览器而言它们不存在 2. 如果“.removeChild()”之前的部分内联代码抛出一个例外,img 元素将不会被删除。
2021-02-21 15:58:52
当插入到 ajax 请求的结果中时,对我不起作用:缺少语法错误;脚本字符串开头的 before 语句
2021-03-01 15:58:52
在一个onload属性里面写很多代码不是很实用此外,这需要存在并加载附加文件。momo 的解决方案不是妥协。
2021-03-04 15:58:52
您可以 Base64 将您的触发图像编码为<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7">(这不会执行网络请求)实际上……您不需要图像,引用不存在的图像而不是onload使用onerror(但这会执行网络请求)
2021-03-04 15:58:52

您可以创建脚本,然后注入内容。

var g = document.createElement('script');
var s = document.getElementsByTagName('script')[0];
g.text = "alert(\"hi\");"
s.parentNode.insertBefore(g, s);

这适用于所有浏览器:)

谁说它来自另一个脚本?您可以在没有<script>元素的情况下运行 JavaScript 例如<img onerror="..." src="#"><body onload="...">如果您想成为技术人员,由于不明确的命名空间,这在非 HTML/SVG 文档中不起作用。
2021-02-09 15:58:52
除非文档中没有任何其他脚本元素。使用document.documentElement来代替。
2021-02-16 15:58:52
没有必要,因为您正在从另一个脚本编写脚本。 <script> var g = document.createElement('script'); var s = document.getElementsByTagName('script')[0]; //reference this script g.text = "alert(\"hi\");" s.parentNode.insertBefore(g, s); </script>
2021-02-19 15:58:52
Facebook 在他们的 SDK 中使用了 Pablo 的答案。developer.facebook.com/docs/javascript/quickstart/v2.2#loading
2021-02-21 15:58:52

我使用了这段代码,它工作正常

var arr = MyDiv.getElementsByTagName('script')
for (var n = 0; n < arr.length; n++)
    eval(arr[n].innerHTML)//run script inside div
谢谢。它解决了我将 Disqus 通用代码添加到使用 TinyBox2 Jquery 插件创建的模态弹出窗口的问题。
2021-02-20 15:58:52
不幸的是,当脚本包含稍后将调用的函数时,此解决方案不起作用。
2021-03-08 15:58:52