對前端同學而言,loade,unload,DOMContentLoaded等頁面加載過程中會觸發的事件肯定是都接觸過,不過要是具體問各個事件的區別,我就不是那么能清晰的解答上來的了。正好剛剛在無阻塞腳本那看到了DOMContentLoaded事件,就來翻翻具體文檔詳細看一下各個事件吧。常言道溫故而知新,讓我們一起回頭看一下
觸發時機
先看下各個事件的觸發時機(參考自MDN)
DOMContentLoaded
當初始html文檔完全加載並解析之后觸發,無需等待樣式、圖片、子frame結束。作為明顯的對比,load事件只有一個頁面完全被加載時才觸發。改用DOMContentLoaded的地方常常是load來代替,這是錯誤的。
tips: 有許多通用和獨立的庫提供跨瀏覽器方法來檢測 DOM 是否已准備就緒即ready事件,后面我們可以看下zepto的實現
load
當一個資源及其依賴的資源結束加載時觸發。從這里可以看到需要等待依賴資源的結束加載。
readystatechange
document有readyState屬性來描述document的loading狀態,readyState的改變會觸發readystatechange事件.
-
loading
文檔仍然在加載
-
interactive
文檔結束加載並且被解析,但是想圖片,樣式,frame之類的子資源仍在加載
-
complete
文檔和子資源已經結束加載,該狀態表明將要觸發load事件。
因此,我們同樣可以使用該事件來判斷dom的加載狀態。
但並非所有對象都會經歷 readyState 的這幾個階段,有時候需要
beforeunload
當瀏覽器窗口,文檔或其資源將要卸載時,會觸發beforeunload事件。這個文檔是依然可見的,並且這個事件在這一刻是可以取消的.
如果處理函數為Event對象的returnValue屬性賦值非空字符串,瀏覽器會彈出一個對話框,來詢問用戶是否確定要離開當前頁面(如下示例)。有些瀏覽器會將返回的字符串展示在彈框里,但有些其他瀏覽器只展示它們自定義的信息。沒有賦值時,該事件不做任何響應。
tip:2011年5月25號起,html5中指出,該事件中調用window.alert(), window.confirm(), and window.prompt()方法將會被忽略。
unload
當文檔或者一個子資源將要被卸載時,在beforeunload 、pagehide兩個事件之后觸發。
文檔會處於一個特定狀態。
- 所有資源仍存在 (圖片, iframe 等.)
- 對於終端用戶所有資源均不可見
- 界面交互無效 (window.open, alert, confirm 等.)
- 錯誤不會停止卸載文檔的過程
頁面加載中的執行順序
從上面的定義,我們可以得出一個比較清晰的順序了。
-
頁面加載開始,首先肯定是先發出加載資源的請求,加載未完成之前,不觸發任何事件。
-
document加載結束並解析,此時css等其他資源未加載完成。
此時readyState為'interactive',表明document已經load並解析完成,觸發 readystatechange,然后觸發DOMContentLoaded(在大多數瀏覽器上的表現如此)。捎帶提一句,此時,加載完成且帶有defer標記的腳本,會按順序開始執行。
-
css、img等子資源加載完成之后
此時觸發window.load事件
-
點擊關閉標簽或者刷新時,會依次觸發beforeunload、unload事件。
可能概念看的有點枯燥,還是看下代碼比較清晰。大家可以看下,下面的代碼會依次輸出什么。
<!DOCTYPE html>
<html>
<head>
<title>文檔加載事件</title>
<script>
document.addEventListener("DOMContentLoaded", function (event) {
console.log("初始DOM 加載並解析");
});
window.addEventListener("load", function (event) {
console.log("window 所有資源加載完成");
});
document.onreadystatechange = function () {
console.log(document.readyState)
if (document.readyState === "complete") {
console.log('初始DOM,加載解析完成')
}
}
window.addEventListener("beforeunload", function (event) {
console.log('即將關閉')
event.returnValue = "\o/";
});
window.addEventListener('unload', function (event) {
console.log('即將關閉1');
});
</script>
<link rel="stylesheet" href="./test.css">
</head>
<body>
<div id="root">dom事件</div>
<script src="./index.js"></script>
</body>
</html>
依次輸出如下:
interactive //(index):15
初始DOM 加載並解析 //(index):8
complet//(index):15
初始DOM,加載解析完成//(index):17
window 所有資源加載完成//(index):11
//點擊關閉按鈕
即將關閉
即將關閉2
關於ready
像jquery、zepto等類庫中都有document一個ready方法,來確保我們的操作在初始dom加載之后進行,原生dom定義里是沒有這個api的,是大牛們封裝了一下判斷的過程,提供我們以便利。
有了前面的例子,讓我們猜一下他們是怎么實現的。
-
ready對應的狀態是初始化dom已經加載完成,我們來看一下什么情況下對應該情況。
有下面幾個狀態,complete、interactive 還有一個DOMContentLoaded也是初始dom加載完成,當然還有load事件,顯然這里不會用到它,相對其他狀態而言有點太晚了。
-
確定觸發條件之后,下面的實現就簡單了,判斷就行了。
以zepto為例,我們看下實現:
//聲明變量,不只使用interactive,是因為前面提到這些狀態不一定全部出現
readyRE = /complete|loaded|interactive/
ready: function(callback){
// need to check if document.body exists for IE as that browser reports
// document ready when it hasn't yet created the body element
if (readyRE.test(document.readyState) && document.body) callback($)
else document.addEventListener('DOMContentLoaded', function(){ callback($) }, false)
return this
}
至此,介紹就結束了。對我而言,明了原來不太清楚的概念,希望對大家也有所幫助。