正如您發現的,您分配給innerHTML
的文本中script
標記中的代碼未被執行。有趣的是,儘管在我嘗試過的每個瀏覽器上,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 | Live Source
<!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>
而這裏的your fiddle updated to use the above我們打開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中使用。
如果這是一個沒有JS後備我假設你測試它沒有啓用JavaScript,所以沒有運行的腳本只是邏輯..或我在這裏丟失了什麼? –
類似的問題在這裏:http://stackoverflow.com/q/1197575/575527 – Joseph
@BenjaminGruenbaum這是運行與JS啓用,DOM正確替換警報腳本不運行,另一個。 –