Javascript封裝DOMContentLoaded事件實例
最近在寫一個Javascript的框架,剛把DOMContentLoaded事件封裝好,略帶小興奮,把開發(fā)過程中遇到的原理和兼容性問題做篇筆記,省的忘記到處找。
我們在寫js代碼的時候,一般都會添加window.onload事件,主要是為了在DOM加載完后可以使用getElementById,getElementsByTagName等方法選取DOM元素進(jìn)行操作,但是window.load會等到加載完DOM、腳本、CSS,最后加載完圖片甚至是iframe中的所有資源才會觸發(fā),很多時候網(wǎng)頁的圖片較多較大,要等最后圖片這個耗時大戶加載完才執(zhí)行js明顯有些太遲了,很多時候都會影響用戶體驗。
很多js框架都有個document.ready的功能,像JQuery的$(document).ready()方法,可以在DOM加載完就立即執(zhí)行js代碼,讓圖片自個慢慢加載吧。
document.ready的核心是DOMContentLoaded事件,firefox、chrome、opera、safari、ie9+都可以使用addEventListener(‘DOMContentLoaded',fn,false)進(jìn)行事件綁定,而ie6~8不支持DOMContentLoaded事件,所以要針對ie6~8做兼容性處理。
資料上說ie6~8可以使用document.onreadystatechange事件監(jiān)聽document.readyState狀態(tài)是否等于complete來判斷DOM是否加載完畢,如果頁面中嵌有iframe的話,ie6~8的document.readyState會等到iframe中的所有資源加載完才會變成complete,此時iframe變成了耗時大戶。但是經(jīng)過測試,即使頁面中沒有iframe,當(dāng)readyState等于complete時,實際觸發(fā)的是onload事件而不是DOMContentLoaded事件,對這點表示驚奇。
還好ie有個特有的doScroll方法,當(dāng)頁面DOM未加載完成時,調(diào)用doScroll方法時,就會報錯,反過來,只要一直間隔調(diào)用doScroll直到不報錯,那就表示頁面DOM加載完畢了,不管圖片和iframe中的內(nèi)容是否加載完畢,此法都有效。
如果有多個js文件綁定了document.ready事件,為了防止瀏覽器重復(fù)綁定,同時有序執(zhí)行,可以引入一個事件隊列機制來解決。
以上就是document.ready事件的原理和兼容性問題,下面貼段實例代碼,為了方便理解執(zhí)行過程,使用函數(shù)封裝的模式,執(zhí)行過程都寫在注釋里了,如果有不妥之處歡迎指教。
//保存domReady的事件隊列
eventQueue = [];
//判斷DOM是否加載完畢
isReady = false;
//判斷DOMReady是否綁定
isBind = false;
/*執(zhí)行domReady()
*
*@param {function}
*@execute 將事件處理程序壓入事件隊列,并綁定DOMContentLoaded
* 如果DOM加載已經(jīng)完成,則立即執(zhí)行
*@caller
*/
function domReady(fn){
if (isReady) {
fn.call(window);
}
else{
eventQueue.push(fn);
};
bindReady();
};
/*domReady事件綁定
*
*@param null
*@execute 現(xiàn)代瀏覽器通過addEvListener綁定DOMContentLoaded,包括ie9+
ie6-8通過判斷doScroll判斷DOM是否加載完畢
*@caller domReady()
*/
function bindReady(){
if (isReady) return;
if (isBind) return;
isBind = true;
if (window.addEventListener) {
document.addEventListener('DOMContentLoaded',execFn,false);
}
else if (window.attachEvent) {
doScroll();
};
};
/*doScroll判斷ie6-8的DOM是否加載完成
*
*@param null
*@execute doScroll判斷DOM是否加載完成
*@caller bindReady()
*/
function doScroll(){
try{
document.documentElement.doScroll('left');
}
catch(error){
return setTimeout(doScroll,20);
};
execFn();
};
/*執(zhí)行事件隊列
*
*@param null
*@execute 循環(huán)執(zhí)行隊列中的事件處理程序
*@caller bindReady()
*/
function execFn(){
if (!isReady) {
isReady = true;
for (var i = 0; i < eventQueue.length; i++) {
eventQueue[i].call(window);
};
eventQueue = [];
};
};
//js文件1
domReady(function(){
...
});
//js文件2
domReady(function(){
...
});
//注意,如果是異步加載的js就不要綁定domReady方法,不然函數(shù)不會執(zhí)行,
//因為異步加載的js下載之前,DOMContentLoaded已經(jīng)觸發(fā),addEventListener執(zhí)行時已經(jīng)監(jiān)聽不到了
測試頁面:都加載了兩張很大的圖片,onload需要圖片加載完才能執(zhí)行js,DOMContentLoaded只需等到DOM加載完即可執(zhí)行js??梢源蜷_firebug查看加載過程,每次測試前記得先清理下瀏覽器緩存。
相關(guān)文章
Canvas中繪制Geojson數(shù)據(jù)示例詳解
這篇文章主要為大家介紹了Canvas中繪制Geojson數(shù)據(jù)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-11-11JavaScript下一版本標(biāo)準(zhǔn)ES6的Set集合使用詳解
ES6:全稱ECMAScript 6.0,是JavaScript語言的國際標(biāo)準(zhǔn),JavaScript是ECMAScript的實現(xiàn)。今天我們就來學(xué)習(xí)一下ES6的Set集合的使用2023-02-02對象無length屬性時IE6/IE7中無法將其轉(zhuǎn)換成偽數(shù)組(ArrayLike)
對象無length屬性時IE6/7中無法將其轉(zhuǎn)換成偽數(shù)組(ArrayLike) 的解決方法,需要的朋友可以參考下。2011-07-07關(guān)于字符串和對象互轉(zhuǎn)以及JSON.parse()的坑
這篇文章主要介紹了關(guān)于字符串和對象互轉(zhuǎn)以及JSON.parse()的坑及解決,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-09-09前端實現(xiàn)(excel)xlsx文件預(yù)覽的詳細(xì)步驟
excel的預(yù)覽庫有不少,也都很強大,但是能很簡單實現(xiàn),下面這篇文章主要給大家介紹了關(guān)于前端實現(xiàn)(excel)xlsx文件預(yù)覽的詳細(xì)步驟,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-03-03