原文位址: http://dean.edwards.name/weblog/2005/09/busted/ 我所謂的解決隻是針對兩款主要的浏覽器——IE和Mozilla/Firefox。難道這還不夠嗎? 首先,讓我先定義這個問題。程式員在他們的web應用程式的最開始調用window.onload 事件。對于菜單的動态效果或者更複雜的事情,如郵件系統的初始化,使用這個事件是很平常的。但是問題就在于onload事件會在所有頁面内容(包括圖檔和其它二進制内容)被加載後才會觸發。如果你的頁面包含了大量的圖檔,那麼你可能會發現在頁面激活之前有一個顯著的延遲。我們想做的就是尋找一種方法來确定DOM被完全的加載時不用等待所有那些讨厭的圖檔加載完畢。 Mozilla提供了一個特定的事件DOMContentLoaded。下面的代碼準确的實作了在Mozilla平台下,我們想要解決的問題:
//
Mozilla浏覽器
if
(document.addEventListener)
...
{
document.addEventListener("DOMContentLoaded", init, false);
}
那麼IE怎麼辦呢? IE對
<script>标簽
提供一個非常友善的屬性:defer。這個屬性的意義是訓示IE延遲腳本的加載直到DOM被加載。但是這僅僅對外部腳本起作用。另一個重要的問題是,這個屬性不能使用腳本動态的添加。這意味着,你不能使用DOM方法建立一個腳本并且設定defer屬性,因為這會被忽略。 使用友善的defer屬性,我們能夠建立一個一小段腳本來調用我們的onload事件
<
script
defer src
="ie_onload.js"
type
="text/javascript"
></
script
>
這個外部腳本的内容僅僅是一行代碼,用來調用我們的onload事件:
init();
使用這個方法,這就不算問題了。但是其他浏覽器會忽略defer屬性并立即加載腳本。這裡有一些方法來繞過這個問題。我鐘愛的方法是使用 條件注釋對其他浏覽器隐藏這段腳本。
<!--
[if IE]><script defer src="ie_onload.js"></script><![endif]
-->
IE也支援 條件編譯。下面的JavaScript代碼和上面的HTML是等效的
//
IE浏覽器
/**/
/*@cc_on @*/
/**/
/*@if (@_win32)
document.write("<script defer src=ie_onload.js></script>");
/*@end @*/
到目前為止看起來一切順利?我們現在需要支援其他的浏覽器。我們隻有一個選擇——标準的window.onload事件:
//
其他浏覽器
window.onload
=
init;
現在就剩下一個問題了(誰說這個問題簡單?)。因為對于其他浏覽器我們隻能使用onload事件,但是對于IE和Mozilla,我們會調用兩次init方法。為了避開這個問題,我們應當做一個标志方法,以至于onload事件隻執行一次。是以我們的init方法會像下面的代碼一樣:
function
init()
...
{
//如果這個方法已經被調用過,就推出
if (arguments.callee.done) return;
//标志這個方法以至于我們不會做同樣的事情兩次
arguments.callee.done = true;
// 其他操作
}
;
And that, as they say, is that.
我提供了一個 例子,來證明這個技術。