淺談DOMContentLoaded事件及其封裝方法

咱們在開發時,常常須要檢測頁面是否加載完畢,以確保腳本安全運行,下面咱們就來淺談一下檢測頁面是否加載完畢的那些事件們。web

1. onload 事件

在頁面的全部資源加載完成時,window對象上會觸發一個onload事件。該事件一般被用以執行一些邏輯代碼。好比,你須要經過JS去訪問一個DOM。安全

<script>
    console.log(document.getElementById('name').innerHTML);
</script>
<div id="name">chengxuyuan</div>

上述代碼運行時確定會報錯,由於腳本執行時,id爲name的div尚未加載完成。那麼什麼時機纔是咱們獲取DOM文檔的可靠時機呢?正是咱們上面說道的onload,頁面的onload觸發時,證實頁面文檔流及資源已經徹底加載完畢,此時,獲取在文檔流中的DOM是最「安全」的時機。咱們將上述代碼加以改造,以下:框架

<script>
    window.onload = function () {
        console.log(document.getElementById('myname').innerHTML);
    }
</script>
<div id="myname">chengxuyuan</div>

再次運行時,代碼便不會報錯了。所以,onload事件的實際效果是當頁面解析完DOM樹,而且完成了全部圖片、樣式表、腳本等資源的加載後才被觸發。那麼問題來了,當資源過多過大時,onload會出現比較嚴重的延遲問題,嚴重影響用戶體驗。測試

2. DOMContentLoaded 事件

對比上述狀況,Firefox的DOMContentLoaded事件就更加合理,該方法觸發的時間更早,它在DOM內容加載完後就觸發,無需等待其餘資源的加載完成。code

<script>
    window.onload = function () {
        console.log('頁面資源所有加載完畢');
    }
    document.addEventListener("DOMContentLoaded", function(event) {
        console.log('DOM已被徹底加載和解析');
    });
</script>

上述代碼的執行結果爲依次打印出:對象

DOM已被徹底加載和解析
頁面資源所有加載完畢事件

因而可知,DOMContentLoaded事件能更早地捕獲到DOM加載完成。圖片

目前,Webkit 525以上版本和Opera也包含該方法。此外,它目前已在HTML5中被標準化。但IE仍不支持DOMContentLoadedip

另外,不少JavaScript框架都有document.ready功能,例如jQuery的:資源

$(document).ready(function(){});

它的核心就是DOMContentLoaded事件,可使用:

document.addEventListener("DOMContentLoaded",function(){...},false);

進行事件綁定,但仍是須要針對IE作兼容性處理。

3. onreadystatechange 事件

雖然IE不支持DOMContentLoaded,但它支持onreadystatechange事件,該事件的目的是提供與文檔或元素的加載狀態有關的信息。支持onreadystatechange事件的每一個對象都有一個readyState屬性,可能包含下列5個值中的一個。

  • uninitialized(爲初始化):對象存在但還沒有初始化。

  • loading(正在加載):對象正在加載數據。

  • loaded(加載完畢):對象加載數據完成。

  • interactive(交互):能夠操做對象了,但尚未徹底加載。

  • complete(完成):對象已經加載完畢。

onreadystatechange事件能夠用於檢測DOM是否加載完畢,當document.readyState == 'complete'時,表示DOM加載完成。可是若是頁面中有iframe的話,會等到iframe中的全部資源加載完纔會變成complete。 此時也形成了主頁面的延遲。而且,經測試,即便頁面中沒有iframe, 該方式也與onload至關,依然會等到全部資源下載完畢後才觸發。

4. doScroll方法

不過,IE還有個特有的方法doScroll, 經過間隔調用:

document.documentElement.doScroll("left");

能夠檢測DOM是否加載完成。 當頁面未加載完成時,該方法會報錯,直到doScroll再也不報錯時,就表明DOM加載完成了。該方法更接近DOMContentLoaded的實現。

5. Javascript封裝DOMContentLoaded事件

如下,是JS封裝DOMContentLoaded事件從而達到良好的兼容性的一個簡單的代碼實現。

function ready(fn){

    // 目前Mozilla、Opera和webkit 525+內核支持DOMContentLoaded事件
    if(document.addEventListener) {
        document.addEventListener('DOMContentLoaded', function() {
            document.removeEventListener('DOMContentLoaded',arguments.callee, false);
            fn();
        }, false);
    } 

    // 若是IE
    else if(document.attachEvent) {
        // 確保當頁面是在iframe中加載時,事件依舊會被安全觸發
        document.attachEvent('onreadystatechange', function() {
            if(document.readyState == 'complete') {
                document.detachEvent('onreadystatechange', arguments.callee);
                fn();
            }
        });

        // 若是是IE且頁面不在iframe中時,輪詢調用doScroll 方法檢測DOM是否加載完畢
        if(document.documentElement.doScroll && typeof window.frameElement === "undefined") {
            try{
                document.documentElement.doScroll('left');
            }
            catch(error){
                return setTimeout(arguments.callee, 20);
            };
            fn();
        }
    }
};

對於IE,首先註冊documentonreadystatechange事件,這是爲了不當頁面處於iframe中時,doScroll方法會失效,所以在實現代碼中作了判斷。以後,判斷若是是IE而且頁面不在iframe當中, 則經過setTimeout來不斷的調用:

document.documentElement.doScroll('left');

直到調用成功,表明DOM加載完成。

總結一下,開發時咱們能夠經過封裝DOMContentLoaded事件來檢測頁面DOM是否加載完畢,而後執行邏輯代碼,提高用戶體驗。

相關文章
相關標籤/搜索