正如您所发现的,script
您分配给文本的标签中的代码innerHTML
不会被执行。不过有趣的是,在我尝试过的每个浏览器上,都会创建script
元素并将其放置在 DOM 中。
这意味着很容易编写一个函数来按顺序运行它们,并且不使用eval
它对作用域的奇怪影响:
function runScripts(element) {
var scripts;
// Get the scripts
scripts = element.getElementsByTagName("script");
// Run them in sequence (remember NodeLists are live)
continueLoading();
function continueLoading() {
var script, newscript;
// While we have a script to load...
while (scripts.length) {
// Get it and remove it from the DOM
script = scripts[0];
script.parentNode.removeChild(script);
// Create a replacement for it
newscript = document.createElement('script');
// External?
if (script.src) {
// Yes, we'll have to wait until it's loaded before continuing
newscript.onerror = continueLoadingOnError;
newscript.onload = continueLoadingOnLoad;
newscript.onreadystatechange = continueLoadingOnReady;
newscript.src = script.src;
}
else {
// No, we can do it right away
newscript.text = script.text;
}
// Start the script
document.documentElement.appendChild(newscript);
// If it's external, wait for callback
if (script.src) {
return;
}
}
// All scripts loaded
newscript = undefined;
// Callback on most browsers when a script is loaded
function continueLoadingOnLoad() {
// Defend against duplicate calls
if (this === newscript) {
continueLoading();
}
}
// Callback on most browsers when a script fails to load
function continueLoadingOnError() {
// Defend against duplicate calls
if (this === newscript) {
continueLoading();
}
}
// Callback on IE when a script's loading status changes
function continueLoadingOnReady() {
// Defend against duplicate calls and check whether the
// script is complete (complete = loaded or error)
if (this === newscript && this.readyState === "complete") {
continueLoading();
}
}
}
}
自然脚本不能使用document.write
.
注意我们必须如何创建一个新 script
元素。仅将现有的移动到文档中的其他位置是行不通的,它已被浏览器标记为已运行(即使它没有运行)。
上面的内容适用于大多数innerHTML
在文档正文某处使用元素的人,但它不适用于您,因为您实际上是在document.documentElement
. 这意味着NodeList
我们从这条线回来:
// Get the scripts
scripts = element.getElementsByTagName("script");
...随着我们向document.documentElement
. 所以在你的特殊情况下,你必须先把它变成一个数组:
var list, scripts, index;
// Get the scripts
list = element.getElementsByTagName("script");
scripts = [];
for (index = 0; index < list.length; ++index) {
scripts[index] = list[index];
}
list = undefined;
...稍后continueLoading
,您必须手动从数组中删除条目:
// Get it and remove it from the DOM
script = scripts[0];
script.parentNode.removeChild(script);
scripts.splice(0, 1); // <== The new line
这是一个适用于大多数人(不是你)的完整示例,包括执行函数声明之类的脚本(如果我们使用 会搞砸eval
):Live Copy | 直播源
<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8 />
<title>Run Scripts</title>
</head>
<body>
<div id="target">Click me</div>
<script>
document.getElementById("target").onclick = function() {
display("Updating div");
this.innerHTML =
"Updated with script" +
"<div id='sub'>sub-div</div>" +
"<script src='http://ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js'></scr" + "ipt>" +
"<script>" +
"display('Script one run');" +
"function foo(msg) {" +
" display(msg); " +
"}" +
"</scr" + "ipt>" +
"<script>" +
"display('Script two run');" +
"foo('Function declared in script one successfully called from script two');" +
"$('#sub').html('updated via jquery');" +
"</scr" + "ipt>";
runScripts(this);
};
function runScripts(element) {
var scripts;
// Get the scripts
scripts = element.getElementsByTagName("script");
// Run them in sequence (remember NodeLists are live)
continueLoading();
function continueLoading() {
var script, newscript;
// While we have a script to load...
while (scripts.length) {
// Get it and remove it from the DOM
script = scripts[0];
script.parentNode.removeChild(script);
// Create a replacement for it
newscript = document.createElement('script');
// External?
if (script.src) {
// Yes, we'll have to wait until it's loaded before continuing
display("Loading " + script.src + "...");
newscript.onerror = continueLoadingOnError;
newscript.onload = continueLoadingOnLoad;
newscript.onreadystatechange = continueLoadingOnReady;
newscript.src = script.src;
}
else {
// No, we can do it right away
display("Loading inline script...");
newscript.text = script.text;
}
// Start the script
document.documentElement.appendChild(newscript);
// If it's external, wait for callback
if (script.src) {
return;
}
}
// All scripts loaded
newscript = undefined;
// Callback on most browsers when a script is loaded
function continueLoadingOnLoad() {
// Defend against duplicate calls
if (this === newscript) {
display("Load complete, next script");
continueLoading();
}
}
// Callback on most browsers when a script fails to load
function continueLoadingOnError() {
// Defend against duplicate calls
if (this === newscript) {
display("Load error, next script");
continueLoading();
}
}
// Callback on IE when a script's loading status changes
function continueLoadingOnReady() {
// Defend against duplicate calls and check whether the
// script is complete (complete = loaded or error)
if (this === newscript && this.readyState === "complete") {
display("Load ready state is complete, next script");
continueLoading();
}
}
}
}
function display(msg) {
var p = document.createElement('p');
p.innerHTML = String(msg);
document.body.appendChild(p);
}
</script>
</body>
</html>
这是您的小提琴更新以使用上面我们将其NodeList
转换为数组的地方:
HTML:
<body>
Hello world22
</body>
脚本:
var model = {
'template': '\t\u003chtml\u003e\r\n\t\t\u003chead\u003e\r\n\t\t\t\u003ctitle\u003eaaa\u003c/title\u003e\r\n\t\t\t\u003cscript src=\"http://cdnjs.cloudflare.com/ajax/libs/jquery/1.10.1/jquery.min.js\"\u003e\u003c/script\u003e\r\n\t\t\t\u003cscript type=\u0027text/javascript\u0027\u003ealert($(\u0027body\u0027).html());\u003c/script\u003e\r\n\t\t\u003c/head\u003e\r\n\t\t\u003cbody\u003e\r\n\t\t\tHello world\r\n\t\t\u003c/body\u003e\r\n\t\u003c/html\u003e'
};
document.documentElement.innerHTML = model.template;
function runScripts(element) {
var list, scripts, index;
// Get the scripts
list = element.getElementsByTagName("script");
scripts = [];
for (index = 0; index < list.length; ++index) {
scripts[index] = list[index];
}
list = undefined;
// Run them in sequence
continueLoading();
function continueLoading() {
var script, newscript;
// While we have a script to load...
while (scripts.length) {
// Get it and remove it from the DOM
script = scripts[0];
script.parentNode.removeChild(script);
scripts.splice(0, 1);
// Create a replacement for it
newscript = document.createElement('script');
// External?
if (script.src) {
// Yes, we'll have to wait until it's loaded before continuing
newscript.onerror = continueLoadingOnError;
newscript.onload = continueLoadingOnLoad;
newscript.onreadystatechange = continueLoadingOnReady;
newscript.src = script.src;
} else {
// No, we can do it right away
newscript.text = script.text;
}
// Start the script
document.documentElement.appendChild(newscript);
// If it's external, wait
if (script.src) {
return;
}
}
// All scripts loaded
newscript = undefined;
// Callback on most browsers when a script is loaded
function continueLoadingOnLoad() {
// Defend against duplicate calls
if (this === newscript) {
continueLoading();
}
}
// Callback on most browsers when a script fails to load
function continueLoadingOnError() {
// Defend against duplicate calls
if (this === newscript) {
continueLoading();
}
}
// Callback on IE when a script's loading status changes
function continueLoadingOnReady() {
// Defend against duplicate calls and check whether the
// script is complete (complete = loaded or error)
if (this === newscript && this.readyState === "complete") {
continueLoading();
}
}
}
}
runScripts(document.documentElement);
我今天在阅读您的问题时才想到这种方法。我以前从未见过它使用过,但它适用于 IE6、IE8、Chrome 26、Firefox 20 和 Opera 12.15。