浅谈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是否加载完毕,而后执行逻辑代码,提高用户体验。

相关文章
相关标签/搜索