39

我正在一个网页上进行 AJAX 调用,该调用返回一大块 HTML,例如:

<div>
  <!-- some html -->
  <script type="text/javascript">
    /** some javascript */
  </script>
</div>

我将整个东西插入到 DOM 中,但 JavaScript 没有运行。有没有办法运行它?

一些细节:我无法控制脚本块中的内容(所以我无法将其更改为可以调用的函数),我只需要执行整个块。我无法对响应调用 eval,因为 JavaScript 位于更大的 HTML 块中。我可以做某种正则表达式来分离出 JavaScript,然后在其上调用 eval,但这很糟糕。有人知道更好的方法吗?

4

7 回答 7

18

通过设置元素的 innerHTML 属性添加的脚本不会被执行。尝试创建一个新的 div,设置它的 innerHTML,然后将这个新的 div 添加到 DOM。例如:

<html>
<头部>
<脚本类型='文本/javascript'>
函数 addScript()
{
    var str = "<script>alert('我在这里');<\/script>";
    var newdiv = document.createElement('div');
    newdiv.innerHTML = str;
    document.getElementById('target').appendChild(newdiv);
}
</脚本>
</head>
<正文>
<input type="button" value="add script" onclick="addScript()"/>
<div>你好世界</div>
<div id="target"></div>
</正文>
</html>
于 2008-09-16T19:38:57.847 回答
15

如果您使用响应来填充 div 或其他内容,则不必使用正则表达式。您可以使用 getElementsByTagName。

div.innerHTML = response;
var scripts = div.getElementsByTagName('script');
for (var ix = 0; ix < scripts.length; ix++) {
    eval(scripts[ix].text);
}
于 2008-09-16T19:27:41.633 回答
9

虽然@Ed 接受了答案。不适用于当前版本的 Firefox、Google Chrome 或 Safari 浏览器我设法熟练使用他的示例以调用动态添加的脚本。

必要的更改仅在于将脚本添加到 DOM 的方式。而不是添加它作为innerHTML技巧是创建一个新的脚本元素并将实际脚本内容添加innerHTML到创建的元素,然后将脚本元素附加到实际目标。

<html>
<head>
<script type='text/javascript'>
function addScript()
{
    var newdiv = document.createElement('div');

    var p = document.createElement('p');
    p.innerHTML = "Dynamically added text";
    newdiv.appendChild(p);

    var script = document.createElement('script');
    script.innerHTML = "alert('i am here');";
    newdiv.appendChild(script);

    document.getElementById('target').appendChild(newdiv);
}
</script>
</head>
<body>
<input type="button" value="add script" onclick="addScript()"/>
<div>hello world</div>
<div id="target"></div>
</body>
</html>

这适用于 Firefox 42、Google Chrome 48 和 Safari 9.0.3

于 2016-02-17T16:37:34.177 回答
2

另一种方法是不只是使用 InnerHTML 将 Ajax 调用的返回值转储到 DOM 中。

您可以动态插入每个节点,然后脚本将运行。

否则,浏览器只会假定您正在插入一个文本节点,而忽略脚本。

使用 Eval 是相当邪恶的,因为它需要启动另一个 Javascript VM 实例并 JIT 传递的字符串。

于 2008-09-16T19:36:13.877 回答
1

最好的方法可能是直接通过 DOM 识别和评估脚本块的内容。

不过我会小心.. 如果您正在实施此操作以克服某些场外呼叫的限制,那么您将打开一个安全漏洞。

你实现的任何东西都可能被用于 XSS。

于 2008-09-16T19:33:38.750 回答
0

您可以使用一种流行的 Ajax 库来为您完成此操作。我喜欢原型。您可以将 evalScripts:true 添加为 Ajax 调用的一部分,它会自动发生。

于 2008-09-16T20:09:02.550 回答
0

对于那些喜欢危险生活的人:

// This is the HTML with script element(s) we want to inject
var newHtml = '<b>After!</b>\r\n<' +
  'script>\r\nchangeColorEverySecond();\r\n</' +
  'script>';
  
// Here, we separate the script tags from the non-script HTML
var parts = separateScriptElementsFromHtml(newHtml);

function separateScriptElementsFromHtml(fullHtmlString) {
    var inner = [], outer = [], m;
    while (m = /<script>([^<]*)<\/script>/gi.exec(fullHtmlString)) {
        outer.push(fullHtmlString.substr(0, m.index));
        inner.push(m[1]);
        fullHtmlString = fullHtmlString.substr(m.index + m[0].length);
    }
    outer.push(fullHtmlString);
    return {
        html: outer.join('\r\n'),
        js: inner.join('\r\n')
    };
}

// In 2 seconds, inject the new HTML, and run the JS
setTimeout(function(){
  document.getElementsByTagName('P')[0].innerHTML = parts.html;
  eval(parts.js);
}, 2000);


// This is the function inside the script tag
function changeColorEverySecond() {
  document.getElementsByTagName('p')[0].style.color = getRandomColor();
  setTimeout(changeColorEverySecond, 1000);
}

// Here is a fun fun function copied from:
// https://stackoverflow.com/a/1484514/2413712
function getRandomColor() {
  var letters = '0123456789ABCDEF';
  var color = '#';
  for (var i = 0; i < 6; i++) {
    color += letters[Math.floor(Math.random() * 16)];
  }
  return color;
}
<p>Before</p>

于 2020-08-31T20:04:14.077 回答