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

有个叫“内容”的分区:

<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>
237319 次浏览

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

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

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

You can use an Ajax callback method such as the one in jQuery's Ajax () method to define what to execute when the request finishes.

您所做的不同于从一开始就加载包含 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");
}

Another quick and dirty way is to use Eval () to execute any script code that you've inserted as DOM text if you don't want to use jQuery or other library.

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

另一篇 StackOverflow 的文章也许对你有帮助: 可以用 innerHTML 插入脚本吗?

只要您不尝试将 XHR 返回的 HTML 子集附加到文档中,这种方法对我来说“就是可行的”。(请参阅 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/

我用了这个代码,它工作得很好

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

我在这里有一个类似的职位,Ajax 上的 addEventListener 加载没有 jquery

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

所以..。

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

第二页或第三页也是一样。

下面是将计算文本中所有脚本标记的脚本。

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

如果要注入需要 script 标记的内容,则可能会得到一个 未捕获的语法错误和说非法令牌。为了避免这种情况,请确保转义结束脚本标记中的正斜杠。即:

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

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

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

另一件要做的事情是用一个脚本加载页面,比如:

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

这将加载页面,然后在运行函数时运行脚本并删除事件处理程序。这不会在一个 ajax 加载之后立即运行,但是如果您正在等待用户输入 div 元素,那么这样做就可以了。

PS. Requires Jquery

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

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

Note: I didn't write parameters to $.ajax which you have to adjust 根据你的 Ajax。

我的结论是 HTML 不允许 NESTED 脚本标记。如果你使用 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>

您可以使用 srcdoc 属性将脚本放入 iframe 中 example:

 <iframe frameborder="0" srcdoc="
<script type='text/javascript'>
func();
</script>
</iframe>