比onload更快的DOMContentLoaded,readystatechange,doscroll的DOM加载事件

比onload更快的DOMContentLoaded,readystatechange,doscroll的DOM加载事件

有时候在想,onload是等所有元素加载完以后再执行,但是有时候我们并不想等待这么久才执行,可能有些业务需要在DOM元素加载完成以后马上就要执行。这个时候,就需要比onload更快的事件函数了,那就是DOMContentLoaded,readystatechange,还有doscroll了。这些函数在jQuery中作了兼容性处理,变成了我们众所周知的ready()函数,也就是DOM树建立好以后就马上执行的函数。

一、先来比较一下兼容性

  1. DOMContentLoaded仅支持IE9以及更高的浏览器,基本上所有主流浏览器都支持(chrome,oprea,firefox)
  2. onreadystatechange支持IE4以上以及所有主流浏览器(同上)(但是我电脑没有IE4,只有IE6,我这里对IE6测试后的兼容还好。)
  3. doscroll的兼容性为IE8以下的浏览器。

二、再来比较用法

  1. DOMContentLoaded当然就是字面意思啦,浏览器DOM树形成之后马上就开始执行业务。
  2. readystatechange因为五个状态都是不一定的啦,interactive和complete都是不一定的,所以,还是需要进行一些判断,才能开始业务。
  3. doscroll,为了测试这个诡异的属性,我还特意用了Charles将网速降低,才知道这个函数是通过不断报错,让浏览器知道DOM树还没加载完成。如果不报错了,就是DOM树建立完了。
  4. 执行速度:doscroll > DOMContentLoaded > interactive状态的readystatechange > complete状态的readystatechange

三、是不是该上代码和说明了QAQ

说明:引用了一段github上的代码,这里向作者Diego Perini致谢。
情况:

a.一种是在IE8浏览器下如果页面作为iframe加载的话,只能使用onreadystatechange事件,而不是使用doscroll,因为iframe支持onreadystatechange,没有别的哈哈~~~
b.一种就是作为正常页面加载,不一样的浏览器有不一样的展现形式。

四、上代码

a.首先是作为iframe的父容器的页面:iframe.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>iframe</title>
</head>
<body>
    <iframe src="main.html" frameborder="0"></iframe>
</body>
</html>

b.然后就是可以作为iframe嵌入或者单独作为主页面的页面: main.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>我是测试DOM树加载的</title>
    <script src="DOMContentLoaded.js"></script>
    <style>
        * {
            margin: 0; 
            padding: 0;
        }
        body {
            width: 100%;
            background-color: #eee;
            height: 2000px;
        }
        .mask {
            width: 100%;
            height: 100px;
            background-color: #ff630c;
            text-align: left;
            position: absolute;
            top: 500px;
            left: 0;
            display: none;
        }ˇ
        .absorb-top-bar {
            width: 100%;
            height: 100px;
            background-color: #ff600c;
            opacity: 0.6;
            text-align: center;
            position: absolute;
            top: 500px;
            left: 0;
        }
    </style>
    <script>
      contentLoaded(window, function(){
        console.log("最后是这个货执行了我" + arguments[0]);
      })
    </script>
</head>
<body>
    <div class="absorb-top-bar">我就是用来拖延dom加载的哈哈</div>
    <div class="absorb-top-bar">我就是用来拖延dom加载的哈哈</div>
    <div class="absorb-top-bar">我就是用来拖延dom加载的哈哈</div>
    <div class="absorb-top-bar">我就是用来拖延dom加载的哈哈</div>
    <div class="absorb-top-bar">我就是用来拖延dom加载的哈哈</div>
    <div class="absorb-top-bar">我就是用来拖延dom加载的哈哈</div>
    <div class="absorb-top-bar">我就是用来拖延dom加载的哈哈</div>
    <div class="absorb-top-bar">我就是用来拖延dom加载的哈哈</div>
    <div class="absorb-top-bar">我就是用来拖延dom加载的哈哈</div>
    <div class="absorb-top-bar">我就是用来拖延dom加载的哈哈</div>
    <div class="absorb-top-bar">我就是用来拖延dom加载的哈哈</div>
    <div class="absorb-top-bar">我就是用来拖延dom加载的哈哈</div>
    <div class="absorb-top-bar">我就是用来拖延dom加载的哈哈</div>
    <div class="absorb-top-bar">我就是用来拖延dom加载的哈哈</div>
    <div class="absorb-top-bar">我就是用来拖延dom加载的哈哈</div>
    <div class="absorb-top-bar">我就是用来拖延dom加载的哈哈</div>
    <div class="absorb-top-bar">我就是用来拖延dom加载的哈哈</div>
    <div class="absorb-top-bar">我就是用来拖延dom加载的哈哈</div>
    <div class="absorb-top-bar">我就是用来拖延dom加载的哈哈</div>
    <div class="absorb-top-bar">我就是用来拖延dom加载的哈哈</div>
    <div class="absorb-top-bar">我就是用来拖延dom加载的哈哈</div>
    <div class="absorb-top-bar">我就是用来拖延dom加载的哈哈</div>
    <div class="absorb-top-bar">我就是用来拖延dom加载的哈哈</div>
    <div class="absorb-top-bar">我就是用来拖延dom加载的哈哈</div>
    <div class="absorb-top-bar">我就是用来拖延dom加载的哈哈</div>
    <div class="absorb-top-bar">我就是用来拖延dom加载的哈哈</div>
    <div class="absorb-top-bar">我就是用来拖延dom加载的哈哈</div>
    <div class="absorb-top-bar">我就是用来拖延dom加载的哈哈</div>
    <div class="absorb-top-bar">我就是用来拖延dom加载的哈哈</div>
    <div class="absorb-top-bar">我就是用来拖延dom加载的哈哈</div>
    <div class="absorb-top-bar">我就是用来拖延dom加载的哈哈</div>
    <div class="absorb-top-bar">我就是用来拖延dom加载的哈哈</div>
    <div class="absorb-top-bar">我就是用来拖延dom加载的哈哈</div>
    <div class="absorb-top-bar">我就是用来拖延dom加载的哈哈</div>
    <div class="absorb-top-bar">我就是用来拖延dom加载的哈哈</div>
    <div class="absorb-top-bar">我就是用来拖延dom加载的哈哈</div>
    <div class="absorb-top-bar">我就是用来拖延dom加载的哈哈</div>
    <div class="absorb-top-bar">我就是用来拖延dom加载的哈哈</div>
    <div class="absorb-top-bar">我就是用来拖延dom加载的哈哈</div>
    <div class="absorb-top-bar">我就是用来拖延dom加载的哈哈</div>
    <div class="absorb-top-bar">我就是用来拖延dom加载的哈哈</div>
    <div class="absorb-top-bar">我就是用来拖延dom加载的哈哈</div>
    <div class="absorb-top-bar">我就是用来拖延dom加载的哈哈</div>
    <div class="absorb-top-bar">我就是用来拖延dom加载的哈哈</div>
    <div class="absorb-top-bar">我就是用来拖延dom加载的哈哈</div>
    <div class="absorb-top-bar">我就是用来拖延dom加载的哈哈</div>
    <div class="absorb-top-bar">我就是用来拖延dom加载的哈哈</div>
    <div class="absorb-top-bar">我就是用来拖延dom加载的哈哈</div>
    <div class="absorb-top-bar">我就是用来拖延dom加载的哈哈</div>
    <div class="absorb-top-bar">我就是用来拖延dom加载的哈哈</div>
    <div class="absorb-top-bar">我就是用来拖延dom加载的哈哈</div>
    <div class="absorb-top-bar">我就是用来拖延dom加载的哈哈</div>
    <div class="absorb-top-bar">我就是用来拖延dom加载的哈哈</div>
</body>
</html>

c.做了兼容性处理的js:DOMContentLoaded.js:

/*!
 * contentloaded.js
 *
 * Author: Diego Perini (diego.perini at gmail.com)
 * Summary: cross-browser wrapper for DOMContentLoaded
 * Updated: 20101020
 * License: MIT
 * Version: 1.2
 *
 * URL:
 * http://javascript.nwbox.com/ContentLoaded/
 * http://javascript.nwbox.com/ContentLoaded/MIT-LICENSE
 * github: https://github.com/dperini/ContentLoaded/blob/master/src/contentloaded.js
 *
 */

// @win window reference
// @fn function reference
// 参数:win(窗口window),fn(加载完成之后执行的函数)
function contentLoaded(win, fn) {
    //执行完成判断 
    var done = false,
        top = true, //判断当前窗口是否在顶层窗口,不是的话报错

        doc = win.document,
        root = doc.documentElement,
        modern = doc.addEventListener, //高级浏览器和低级浏览器判断变量

        add = modern ? 'addEventListener' : 'attachEvent',
        rem = modern ? 'removeEventListener' : 'detachEvent',
        pre = modern ? '' : 'on',

        init = function(e) {
            // 输出执行的事件类型
            console.log(e.type ? e.type : e);

            //输出readystatechange的状态
            if (e.type == 'readystatechange') {
                console.log(doc.readyState);
            }

            // 保证每个预加载的事件只执行一次fn,包括DOMContentLoaded。但是保证init事件不再在load事件中执行。
            if (e.type == 'readystatechange' && doc.readyState != 'complete') return;

            // 将onload同名的加载事件清除掉,防止又执行一次,作者这倒是想的很周到啊
            (e.type == 'load' ? win : doc)[rem](pre + e.type, init, false);

            // 下面是DOMContentLoaded或者readystatechange真正完成的时候才会执行,或者更低级浏览器完成
            // 时执行
            if (!done && (done = true)) {
                console.log('我已经被' + e.type + '执行了');
                fn.call(win, e.type || e);
            }
        },

        poll = function() {

            // ie7以及以下的浏览器使用doscroll进行模拟domcontentloaded
            try { root.doScroll('left'); } catch (e) {
                console.log('低版本浏览器还没有加载完成,继续递归执行至加载完成');
                // 因为间隔50毫秒时间还是相对较长的,可能这个时候readystatechange已经提早执行了
                setTimeout(poll, 50);
                return;
            }

            console.log('加载完成,可以使用readystatechange');

            // 下面是保证低级浏览器如果不支持readystatechange的情况下,一定会执行这个init函数
            init('poll');
        };

    // 如果文档readyState为complete代表load事件准备被触发,所以这个时候可以直接执行要执行的函数了
    if (doc.readyState == 'complete') {
        fn.call(win, 'lazy');
    } else {
        // 不是最新的浏览器,进行doScroll加载
        // 可以使用Charles中国年的Throttle Settings来限速实现执行这个函数,我是限速到10kb
        if (!modern && root.doScroll) {
            console.log('低版本浏览器执行doScroll!');
            //判断当前窗口是否插入到了iframe窗口,因为这个属性兼容性未知,需要用try防止出错
            try { top = !win.frameElement; } catch (e) {}
            // 如果当前窗口是以iframe插入到窗口中的,那么应该使用readystatechange
            if (top) poll();
        }
        console.log('IE9及更高级浏览器的DOMContentLoaded,走你!');
        doc[add](pre + 'DOMContentLoaded', init, false); //只有ie9以及更高版本支持
        console.log('默认走一次的readystatechange');
        doc[add](pre + 'readystatechange', init, false); //兼容ie8以及更低的浏览器
        console.log('默认走一次的onload');
        win[add](pre + 'load', init, false); //高级浏览器清除win的onload中执行的函数,IE浏览器清除doc中的onload函数
    }

}

五、浏览器测试情况

  1. 首先是各主流浏览器执行情况(不作为iframe嵌入到页面中):

    Chrome:

    chrome测试

    Firefox:

    ff测试

    Opera

    Opera测试

    IE8:

    IE8测试

    IE7:

    IE7测试

    IE6:

    IE6测试

  2. 其次是在IE下作为一个iframe嵌入到页面中的情况:

    IE8:

    IE8中作为iframe

    IE7:

    IE7中作为iframe

    IE6:

    IE6中作为iframe

六、总结

可见,需要先了解清楚这三种加载函数的优先级和兼容性,才能更好地为业务作为准备,示例中如果有不合理或者可以完善的地方,欢迎各位提意见。谢谢大家的收看~~~

©️2020 CSDN 皮肤主题: 编程工作室 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值