在AJAX调用后执行innerHTML注入的<script>


100

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

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

应该用AJAX填充来自PHP文件的数据,包括<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>

您如何加载div?取决于您使用的库,通常可以控制是否只希望在ajax加载后执行脚本。
Bill Yang

1
之后window.onload我创建了一个XMTHttpRequest对象要求另一个(PHP)页面包含div的内容,包括脚本。我正在使用普通的JS来执行此操作,没有任何库(我自己的哈哈除外)
JCOC611

Answers:


65

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

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


您可以选择所有已加载的脚本并通过eval()函数执行它们:$('#audit-view script').each(function (index, element) { eval(element.innerHTML); })
Jerzy Gebler 2015年

绝对应执行添加到页面的Javascript。(例如jsfiddle.net/wnn5fz3m/1)。问题是为什么有时不这样做?
NoBugs 2015年

@Chocula我将我的脚本移到了一个单独的文件,但是它仍然无法正常运行,您能帮上忙吗?stackoverflow.com/questions/42941856/…–
Samra

仅供参考(@NoBugs给了我一个线索)。我尝试了简单的javascirpt element.innerHTML = zzz和设计工作。然后,我尝试Jquery $(element).html(zzz)并工作。
gtryonp

66

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

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

4
如果您问我,这是一个比公认的更好的答案。这几乎是JavaScript注入。
Xedret

虽然有用,但这确实不能回答为什么脚本无法运行的问题。例如,请参见jsfiddle.net/fkqmcaz7jsfiddle.net/wnn5fz3m/1,它绝对应该运行,并且我找不到它不起作用的简化情况。
NoBugs

1
@NaoiseGolden OP确实是在询问脚本的执行情况,所以我认为这里还可以。:-)
dayturns '16

1
强烈不建议使用Eval()。请参阅本- stackoverflow.com/questions/9107847/...
国王

15

如果您通过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文本插入的任何脚本代码。


使用jQuery的回调,如何“执行”新<script>中的代码?
JCOC611

我添加了一个使用成功回调的示例:
Christopher Tokar,

1
非常感谢!“ myFunction();” 部分是我遗漏了代码。
杰森

11

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

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


5

只要您不尝试将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/


1
这极不可能是当前解决该问题的方法,因为那是真正老版本的jQuery的错误。
NoBugs 2015年

3

这是一个可以用来解析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;
 }

2

如果要注入需要script标记的内容,则可能会出现未捕获的语法错误并说出非法标记。为避免这种情况,请确保在结束脚本标记中转义正斜杠。即

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

对于任何结束标签(例如表单标签)也是如此。


0

我在这里有一个类似的帖子,没有使用jquery在ajax上加载addEventListener

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

所以...

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

然后第2或3页相同。


0

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

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

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


0

我的结论是HTML不允许使用NESTED SCRIPT标签。如果您使用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>

-3

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

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

这将加载页面,然后运行脚本并在函数运行后删除事件处理程序。加载ajax后,该操作将不会立即运行,但是如果您正在等待用户输入div元素,则此操作就可以了。

PS。需要jQuery

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.