【问题标题】:Dynamically executing a <script> tag with an external src attribute using eval使用 eval 动态执行具有外部 src 属性的 <script> 标记
【发布时间】:2019-08-04 05:49:53
【问题描述】:

我正在使用Genius API 来检索给定歌曲的歌词并将它们嵌入到 HTML &lt;div&gt; 标记中。我正在通过 AJAX GET 请求使用 PHP 与此 API 进行交互。

如果 AJAX 请求成功,我会从我的 PHP 中检索以下 HTML:

<div id='rg_embed_link_2351532' class='rg_embed_link' data-song-id='2351532'>
    Read <a href='https://genius.com/The-1975-the-sound-lyrics'>“The Sound” by The 1975</a> on Genius
</div> 
<script crossorigin src='//genius.com/songs/2351532/embed.js'></script>

Genius API 返回的脚本标签在执行时会嵌入歌词和歌词信息。

我正在尝试将此 HTML 导入我现有的&lt;div&gt;。在这种情况下,&lt;script&gt; 部分将不会被执行。我尝试在 AJAX 的“成功”函数中使用 eval() 来动态执行此脚本,但没有成功:

$.ajax({
    url: 'lyrics.php',
    type: 'GET',
    async: true,
    success: function(success){
        geniusHTML = success;

        //Insert geniusHTML including script tag into div
        var lyricsDiv = document.getElementById("lyricsDiv");
        lyricsDiv.innerHTML = geniusHTML;

        //Get the script tag from the html and use eval on it
        var innerScript = lyricsDiv.getElementsByTagName('script')
        eval(innerScript.outerHTML);
    }
});

我已尝试评估:

  • .outerHTML -- 控制台显示此值为:&lt;script crossorigin="" src="//genius.com/songs/2351532/embed.js"&gt;&lt;/script&gt;
  • .innerHTML -- 属性似乎为空。
  • .src -- 控制台显示此值为:http://genius.com/songs/2351532/embed.jseval() 函数在此使用 Uncaught SyntaxError: Unexpected end of input 时出错。

我觉得我可能会倒退。我应该从我的 AJAX 执行脚本返回 之前 我将它添加到 div 吗? (该脚本生成了相当多的 embed div 标签)

编辑

根据回答者 Sjoerd de Wit 的指示,我尝试从源标签的 src 属性创建一个新的脚本标签,并通过 document.head.appendChild 添加它。这不起作用,提供警告:

在“文档”上执行“写入”失败:无法写入 从异步加载的外部脚本到文档中,除非 它是显式打开的。

【问题讨论】:

  • eval() == evil()。不要使用它。您可以在互联网上到处阅读为什么使用它不好。
  • @MarkBaijens 注意!

标签: javascript php jquery html ajax


【解决方案1】:

解决方案
回答我自己的问题。

这个问题的其他答案是完全可以接受的,并且在大多数情况下都有效。但是,如果外部 .js 文件中包含 document.write,您的浏览器将向您发出以下警告:

在“文档”上执行“写入”失败:除非显式打开,否则无法从异步加载的外部脚本写入文档。

解决此问题的方法之一是使用Postscribe。 Postscribe 将覆盖传递给它的 javascript 中的任何 document.write 实例。

在我的代码上下文中——请放心,我将对其进行重构以使其更高效——我通过获取元素的 outerHTML 从 div 中检索我的脚本标签,然后将其传递给 postscribe。

在这个用例中,postscribe 接受两个参数;将脚本传递给的 div 以及脚本本身。当然——你可以通过内联或变量传递脚本,就像我在下面的例子中所做的那样:

var myScript = myDiv.getElementsByTagName('script')[0].outerHTML;
postscribe('#myDiv', myScript);

有关安装说明和更多功能,请参阅上面链接的 postscribe 文档。

【讨论】:

    【解决方案2】:

    使用 jQuery 的 .html() 而不是 javascript 的 .innerHTML() 将自动评估字符串中的脚本

    所以,试着改变这一行

    //Insert geniusHTML including script tag into div
    var lyricsDiv = document.getElementById("lyricsDiv");
    lyricsDiv.innerHTML = geniusHTML;
    
    //Get the script tag from the html and use eval on it
    var innerScript = lyricsDiv.getElementsByTagName('script')
    eval(innerScript.outerHTML);
    

    进入

    $("#lyricsDiv").html(geniusHTML);
    

    【讨论】:

    • 感谢 scott - 这行得通,但我仍然收到编辑中提到的警告。但是,此警告似乎是与document.write 相关的单独问题。接受这是在这种情况下的最佳答案。
    【解决方案3】:

    您应该从脚本标签中获取 src 并在您的 html 中动态创建和加载它

    var script = document.createElement("script");  
    var innerScript = lyricsDiv.getElementsByTagName('script')
    script.src = innerScript.src; 
    
    document.head.appendChild(script); 
    

    【讨论】:

    • 感谢您的评论!这不适用于包含嵌入的脚本 - 请参阅我在后期编辑中发布的警告。
    • 感谢@Mark Ba​​ijens,这解释了警告。我不认为我可以重构 Genius 提供的脚本,但我会按照答案中的说明尝试 postscribe。干杯!
    猜你喜欢
    • 2015-03-22
    • 2016-07-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-29
    • 2012-06-24
    • 2010-09-10
    • 2023-03-12
    相关资源
    最近更新 更多