【问题标题】:Executing <script> injected by innerHTML after AJAX call在 AJAX 调用后执行由 innerHTML 注入的 <script>
【发布时间】:2011-06-04 21:58:35
【问题描述】:

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

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

它应该由 AJAX 填充来自 PHP 文件的数据,包括 &lt;script&gt; 标记。但是,该标签内的脚本并没有被执行。

<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 加载后执行脚本。
  • window.onload 之后,我创建了一个XMTHttpRequest 对象来请求另一个(php) 页面,该页面包含div 的内容,包括一个脚本。我用普通的 JS 做这个,没有库(除了我自己的哈哈)

标签: javascript html ajax


【解决方案1】:

如果您像这样通过 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 的回调,我如何“执行”新
  • 我添加了一个使用成功回调的例子:
  • 非常感谢! “我的函数();”部分是我在代码中遗漏的部分。
【解决方案2】:

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

其他 StackOverflow 帖子也可能对您有所帮助:Can scripts be inserted with innerHTML?

【讨论】:

  • 可以选择所有加载的脚本并通过eval()函数执行:$('#audit-view script').each(function (index, element) { eval(element.innerHTML); })
  • 添加到页面的Javascript绝对应该执行。 (例如jsfiddle.net/wnn5fz3m/1)。问题是为什么有时不呢?
  • @Chocula 我将我的脚本移到了一个单独的文件中,但它仍然不能从部分工作你能帮忙吗? stackoverflow.com/questions/42941856/…
  • 仅供参考(@NoBugs 给了我一个线索)。我尝试了普通的 javascirpt element.innerHTML=zzz 和 desnt 工作。然后我尝试了 Jquery $(element).html(zzz) 并工作了。
【解决方案3】:

如果您不尝试将 XHR 返回的 HTML 的子集附加到文档中,那么这对使用 jQuery 的我来说“很有效”。 (请参阅 this bug report 显示 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/

【讨论】:

  • 极不可能解决当前的问题,因为这是 jQuery 的真正旧版本的错误。
【解决方案4】:

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

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

【讨论】:

  • 如果你问我,这是一个比公认的更好的答案。这几乎是 JavaScript 注入。
  • 虽然有用,但这并不能回答为什么脚本不会运行的问题。参见例如 jsfiddle.net/fkqmcaz7jsfiddle.net/wnn5fz3m/1 它绝对应该运行,而且我没有找到它不起作用的简化案例。
  • @NaoiseGolden OP 从字面上询问脚本执行,所以我认为这里没问题。 :-)
  • Eval() 不被强烈推荐。看到这个 - stackoverflow.com/questions/9107847/…
【解决方案5】:

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

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

所以...

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

那么第 2 页或第 3 页也一样。

【讨论】:

    【解决方案6】:

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

    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

    【讨论】:

      【解决方案7】:

      如果你要注入一些需要脚本标签的东西,你可能会得到一个未捕获的语法错误并说非法令牌。为避免这种情况,请务必在结束脚本标记中转义正斜杠。即;

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

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

      【讨论】:

        【解决方案8】:

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

        【讨论】:

          【解决方案9】:

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

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

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

          PS。需要 Jquery

          【讨论】:

            【解决方案10】:

            这对我有用,方法是从 ajax .done 对每个脚本内容调用 eval :

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

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

            【讨论】:

              【解决方案11】:

              我的结论是 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>
              

              【讨论】:

                猜你喜欢
                • 2023-02-02
                • 2020-06-06
                相关资源
                最近更新 更多