2009-12-17 94 views
2

背景

我正在研究一個項目,該項目在資源有限的小型設備的嵌入式Web瀏覽器中運行。瀏覽器本身有點過時並且其功能有限(HTML 4.01†,W3C DOM Level 2†,JavaScript 1.4)。我沒有關於瀏覽器的文檔,所以我所知道的是來自試驗和錯誤。創建動態JavaScript的替代方法?

重點是從服務器檢索動態內容,以便只需要將最少量的不靈活代碼嵌入到運行Web瀏覽器的設備中。瀏覽器不支持XMLHTTPRequest對象,所以AJAX沒有了。與我一起工作,我寫了一些測試代碼來動態插入JavaScript。

†這些標準不支持

編輯 雖然我不能實際確認的話,我相信this site可以列出了嵌入式瀏覽器的DOM支持,因爲我看「的Mozilla/4.0(兼容小部分; EBSWebC 2.6; Windows NT 5.1)「作爲服務器日誌中的用戶代理。

<html> 
<head> 
</head> 
<body onload="init()"> 
<div id="root"></div> 
<script type="text/javascript"> 
<!-- 
function init() { 
// Add a div element to the page. 
var div = document.createElement("div"); 
div.id = "testDiv"; 
document.getElementById("root").appendChild(div); 

// Set a timeout to insert the JavaScript after 2 seconds. 
setTimeout("dynamicJS()", 2000); 
} 

function dynamicJS() { 
... 
} 
//--> 
</script> 
</body> 
</html> 

方法1

我最初實現使用方法1dynamicJS功能,發現同時代碼按預期執行在Chrome,IE8和Firefox 3.5時,JavaScript實際上沒有由所檢索的嵌入式瀏覽器,當元素被追加時。

function dynamicJS() { 
var js = document.createElement("script"); 
js.type = "text/javascript"; 
js.src = "js/test.js"; 
document.getElementById("root").appendChild(js); 
} 

方法2

尋找周圍的工作,我實現方法2。該方法實際上在嵌入式瀏覽器中工作,因爲JavaScript被檢索和執行,但在我測試的其他現代Web瀏覽器(Chrome,IE8,FireFox 3.5)中無法正常工作。

function dynamicJS() { 
var js= '<script type="text/javascript" src="js/test.js"> </s' + 'cript>'; 
document.getElementById("testDiv").innerHTML = js; 
} 

問題

我是新來的JavaScript和一般的網絡編程,所以我希望專家們的一個(或多個)在這裏可以提供一些線索這對我來說。

方法2是否在技術上有問題?如果沒有,爲什麼它在現代Web瀏覽器中不起作用?

+0

這可能不是這樣,但是如果瀏覽器沒有解析腳本標記,如果它裏面沒有內容,那麼過去我遇到了一些問題。當我將它包含在頁面中時,我會在腳本標記內放置一個「空格」。也許用method1,你可以設置js.innerText ='';或在Method2中,在腳本標記之間添加一個空格。 – 2009-12-17 19:58:59

回答

2

innerHTML屬性尚未真正得到規範,但所有現代瀏覽器都支持它,和HTML5的標準草案包括a definition of how it should work。根據HTML5 specification

當使用document.write()方法插入,script元件執行(通​​常同步地),但使用innerHTMLouterHTML屬性插入時,它們不會在所有執行。

innerHTML在Microsoft Internet Explorer 4中首次引入,並且由於它的普及作家中,已經通過了所有其他的瀏覽器,這是導致其納入HTML5的。所以,讓我們檢查Microsoft's documentation

當使用的innerHTML插入腳本,你必須包括script元素的DEFER屬性。

因此很明顯,在IE中你可以得到腳本通過innerHTML插入執行,但只有當你添加一個defer屬性(我沒有IE瀏覽器在我的面前,以測試這一點)。 defer是首次添加到IE中的另一個功能;它是included in HTML 4.01,但在其他瀏覽器中並沒有找到相當長的一段時間。 包含更詳細的描述,說明<script defer>應該如何工作,儘管它似乎與它在IE中的工作方式略有不兼容,因爲它不允許執行通過innerHTML添加的腳本。 HTML5的定義爲<script defer>appears to be implemented in Firefox 3.5 and Safari 4

總之,innerHTML還沒有真正被標準化,而是由所有瀏覽器供應商以稍微不同的方式實現。在IE中,原來的實現,除了defer屬性之外,它不支持腳本的執行,defer直到最近才被其他瀏覽器支持,所以其他瀏覽器根本不支持腳本的添加innerHTML。這種行爲是HTML5標準化的,因此除非Microsoft對象可能會成爲標準。

聽起來好像你正在使用的瀏覽器沒有做好兼容innerHTML的工作,因爲它執行使用innerHTML添加的腳本,無論如何。這並不令人驚訝,因爲行爲不規範,因此需要通過閱讀其他瀏覽器的文檔(過去可能沒有包括這個事實)來反向設計或收集。HTML5的主要目標之一是實際寫下所有這些不成文的假設和未記錄的行爲,以便將來有人實現瀏覽器時可以這樣做,而不會被不符合實際的規範所誤導,或者沒有做現有瀏覽器的逆向工程。

它看起來對我說,你可能需要使用方法2你的嵌入式瀏覽器,並方法1,如果你想在常見的桌面瀏覽器上運行。如果這樣做不起作用,那麼首先嚐試方法1,然後回退到方法2,如果兩者都不起作用,然後出錯(或根據您的需要靜默失敗),則可能是個好主意。

3

方法2沒有什麼技術上的錯誤,但大多數現代瀏覽器都有非常鬆散的HTML解析器,這些解析器往往會陷入您要發送的代碼中。具體來說,他們將JavaScript字符串文字中的</script>解析爲結束標記。這體現在兩個方面:

  1. 您將看到「Unterminated String Literal」錯誤。
  2. </script>文本後的所有代碼將在頁面上呈現爲文本。

此問題的常用解決方法是拆分</script>。你可以用下面的代碼來做到這一點。是的,我知道它是一個黑客,但它解決了這個問題。

function dynamicJS() { 
    var js= '<script type="text/javascript" src="js/test.js"></s' + 'cript>'; 
    document.getElementById("testDiv").innerHTML = js; 
} 

實際上,您應該能夠嚴格使用您的第一種方法嚴格使用DOM API。我發現某些瀏覽器可能對加載腳本的腳本非常挑剔,因爲它們只會在它們被放置爲<head>元素的子元素時加載它們。這是YUILoader的工作方式,所以如果它在所有瀏覽器中都不起作用,我會感到驚訝。

下面是一個例子,你要檢查這個以確保它在所有的瀏覽器,並添加一些錯誤周圍的假設檢驗,將有一個<head>元素,但它給你的總體思路。

if (!document.getElementsByTagName) { 
    document.getElementsByTagName = function(name) { 
    var nodes = []; 
    var queue = [document.documentElement]; 
    while (queue.length > 0) { 
     var node = queue.shift(); 
     if (node.tagName && node.tagName.toLowerCase() === name) { 
     nodes.push(node); 
     } 
     if (node.childNodes && node.childNodes.length > 0) { 
     for (var i=0; i<node.childNodes.length; i++) { 
      if (node.childNodes[i].nodeType === 1 /* element */) { 
      queue.push(node.childNodes[i]); 
      } 
     } 
     } 
    } 
    return nodes; 
    }; 
} 

function dynamicJS() { 
    var js = document.createElement("script"); 
    js.setAttribute('type', 'text/javascript'); 
    js.setAttribute('src', 'js/test.js'); 
    var head = document.getElementsByTagName('head')[0]; 
    head.appendChild(js); 
} 
+0

我無法讓您的解決方法在IE8,Chrome或FireFox 3.5中運行。 IE8不顯示該元素已添加。 Chrome顯示該元素已添加,但未檢索到JavaScript(服務器日誌證實了這一點)。使用Firebug與FireFox 3.5,我看到元素被添加,並且錯誤消息表示它無法加載源(服務器日誌確認這一點)。 這種動態插入JavaScript的方法似乎只適用於嵌入式瀏覽器。 – jschmier 2009-12-17 18:26:13

+0

如果瀏覽器本身沒有它,我已經添加了getElementsByTagName()的實現。我已經測試過它,它可以在IE,FF和Chrome中使用,只要在文檔完全加載之後纔打電話 - 只需在超時或腳本標記中將其稱爲文檔末尾即可。 – 2009-12-17 19:48:25

+0

我更新了方法2以顯示我所嘗試的內容。它仍然不適用於現代瀏覽器,我仍然很好奇爲什麼。 – jschmier 2009-12-18 00:07:15

0

一個遠射,但嵌入式瀏覽器支持iframe? 如果是這樣,你將能夠使用它來加載你需要的任何額外的JS並通過iframe訪問它?