繁体   English   中英

执行<script> injected by innerHTML after AJAX call

[英]Executing <script> injected by innerHTML after AJAX call

有一个名为“内容”的 div:

<div id="content"></div>

它应该用来自 PHP 文件的数据填充,通过 AJAX,包括一个<script>标签。 但是,该标签内的脚本没有被执行。

<div id="content"><!-- After AJAX loads the stuff that goes here -->
   <script type="text/javascript">
     //code
   </script>
   <!-- More stuff that DOES work here -->
</div>

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

var arr = MyDiv.getElementsByTagName('script')
for (var n = 0; n < arr.length; n++)
    eval(arr[n].innerHTML)//run script inside div

作为 DOM 文本插入的 JavaScript 将不会执行。 但是,您可以使用动态脚本模式来实现您的目标。 基本思想是将要执行的脚本移动到外部文件中,并在获得 Ajax 响应时创建脚本标记。 然后设置脚本标签的src属性,瞧,它加载并执行外部脚本。

这篇 StackOverflow 的其他帖子也可能对您有所帮助: 可以使用 innerHTML 插入脚本吗? .

如果您通过 Ajax 在 div 中加载脚本块,如下所示:

<div id="content">
    <script type="text/javascript">
    function myFunction() {
      //do something
    }
    myFunction();
    </script>
</div>

...它只是更新页面的 DOM,myFunction() 不一定会被调用。

您可以使用 Ajax 回调方法(例如 jQuery 的ajax()方法中的方法)来定义在请求完成时要执行的内容。

您正在做的事情不同于从一开始就加载包含 JavaScript 的页面(确实会被执行)。

获取一些内容后如何使用成功回调和错误回调的示例:

  $.ajax({
    type: 'GET',
    url: 'response.php',
    timeout: 2000,
    success: function(data) {
      $("#content").html(data);
      myFunction();
    },
    error: function (XMLHttpRequest, textStatus, errorThrown) {
      alert("error retrieving content");
    }

如果您不想使用 jQuery 或其他库,另一种快速而肮脏的方法是使用eval()执行您作为 DOM 文本插入的任何脚本代码。

这是将评估文本中所有脚本标记的脚本。

function evalJSFromHtml(html) {
  var newElement = document.createElement('div');
  newElement.innerHTML = html;

  var scripts = newElement.getElementsByTagName("script");
  for (var i = 0; i < scripts.length; ++i) {
    var script = scripts[i];
    eval(script.innerHTML);
  }
}

从服务器收到 HTML 后,只需调用此函数即可。 请注意:使用eval可能很危险。

演示: http : //plnkr.co/edit/LA7OPkRfAtgOhwcAnLrl?p=preview

如果您不尝试将 XHR 返回的 HTML 的子集附加到文档中,这对我使用 jQuery 来说“只是有效”。 (请参阅此错误报告,其中显示了 jQuery 的问题。)

这是一个显示它工作的示例:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> 
<html lang="en"> 
<head> 
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> 
    <title>test_1.4</title> 
    <script type="text/javascript" charset="utf-8" src="jquery.1.4.2.js"></script> 
    <script type="text/javascript" charset="utf-8"> 
        var snippet = "<div><span id='a'>JS did not run<\/span><script type='text/javascript'>" +
        "$('#a').html('Hooray! JS ran!');" +
        "<\/script><\/div>";
        $(function(){
            $('#replaceable').replaceWith($(snippet));
        });
    </script> 
</head> 
<body> 
    <div id="replaceable">I'm going away.</div> 
</body> 
</html>

这是上面的等效项: http : //jsfiddle.net/2CTLH/

这是一个可用于解析 AJAX 响应的函数,特别是如果您使用 minifiedjs 并希望它执行返回的 Javascript 或只想解析脚本而不将它们添加到 DOM,它也可以处理异常错误。 我在 php4sack 库中使用了这段代码,它在库之外很有用。

function parseScript(_source) {
    var source = _source;
    var scripts = new Array();

    // Strip out tags
    while(source.toLowerCase().indexOf("<script") > -1 || source.toLowerCase().indexOf("</script") > -1) {
        var s = source.toLowerCase().indexOf("<script");
        var s_e = source.indexOf(">", s);
        var e = source.toLowerCase().indexOf("</script", s);
        var e_e = source.indexOf(">", e);

        // Add to scripts array
        scripts.push(source.substring(s_e+1, e));
        // Strip from source
        source = source.substring(0, s) + source.substring(e_e+1);
    }

    // Loop through every script collected and eval it
    for(var i=0; i<scripts.length; i++) {
        try {
          if (scripts[i] != '')
          {         
            try  {          //IE
                  execScript(scripts[i]);   
      }
      catch(ex)           //Firefox
      {
        window.eval(scripts[i]);
      }   

            }  
        }
        catch(e) {
            // do what you want here when a script fails
         // window.alert('Script failed to run - '+scripts[i]);
          if (e instanceof SyntaxError) console.log (e.message+' - '+scripts[i]);
                    }
    }
// Return the cleaned source
    return source;
 }

如果您正在注入需要脚本标记的内容,您可能会收到一个未捕获的语法错误并说非法令牌 为避免这种情况,请确保转义结束脚本标记中的正斜杠。 IE;

var output += '<\/script>';

任何结束标签也是如此,例如表单标签。

通过对来自 ajax .done 的每个脚本内容调用 eval ,这对我有用:

$.ajax({}).done(function (data) {      
    $('div#content script').each(function (index, element) { eval(element.innerHTML); 
})  

注意:我没有将参数写入 $.ajax,您必须根据您的 ajax 进行调整。

我在这里有一个类似的帖子, addEventListener load on ajax load WITHOUT jquery

我如何解决它是在我的 stateChange 函数中插入对函数的调用。 我设置的页面是 3 个按钮,可以将 3 个不同的页面加载到 contentArea 中。 因为我必须知道按下哪个按钮来加载页面 1、2 或 3,所以我可以轻松地使用 if/else 语句来确定正在加载哪个页面,然后运行哪个函数。 我试图做的是注册不同的按钮侦听器,这些侦听器仅在由于元素 ID 加载特定页面时才起作用。

所以...

如果(page1 正在加载,pageload = 1)运行函数 registerListeners1

然后第 2 页或第 3 页相同。

我的结论是 HTML 不允许嵌套脚本标签。 如果您使用 javascript 来注入包含脚本标签的 HTML 代码,则将无法工作,因为 javascript 也包含在脚本标签中。 你可以用下一个代码测试它,你会发现它不会工作。 用例是您正在使用 AJAX 或类似方法调用服务,您正在获取 HTML 并且您想直接将其注入 HTML DOM 中。 如果注入的 HTML 代码包含在 SCRIPT 标签中,则将无法工作。

<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"></head><body></body><script>document.getElementsByTagName("body")[0].innerHTML = "<script>console.log('hi there')</script>\n<div>hello world</div>\n"</script></html>

另一件事是使用脚本加载页面,例如:

<div id="content" onmouseover='myFunction();$(this).prop( 'onmouseover', null );'>
<script type="text/javascript">
function myFunction() {
  //do something
}
myFunction();
</script>
</div>

这将加载页面,然后运行脚本并在函数运行时删除事件处理程序。 这不会在 ajax 加载后立即运行,但如果您正在等待用户输入 div 元素,这将工作得很好。

附注。 需要jQuery

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM