代码改变世界

jQuery DOMready 页面加载事件 研究

2013-01-13 22:42  VVG  阅读(1416)  评论(0编辑  收藏

jQuery中的ready事件原型,在这里提取出来便于理解,代码+注释 如下:

    // 事件队列
    var EventQueue = null;
    // 是否已经执行过了,只执行一次
    var isFire = false;
    //添加ready事件
    function addReadyEvent(fn){
        if(!EventQueue) EventQueue = [];
        if(document.readyState == 'complete'){
            fn();
        }else{
            EventQueue.push(fn);
        }
    }
    // 触发ready事件
    function fireReadyEvent(){
        if(!isFire){
            var fn,i=0;
            if(EventQueue){
                while(fn = EventQueue[i]){
                    fn();
                    i++;
                }
                EventQueue = null;
            }
            isFire = true;
        }
    }
    // 绑定ready事件
    function bindReady(){
        if(document.addEventListener){
            // 标准浏览器DOM加载完毕后执行队列,并卸载事件
            document.addEventListener('DOMContentLoaded',unbindReady,false);
            // 确保会执行
            window.addEventListener('load',fireReadyEvent,false);
        }else if(document.attachEvent){
            // IE浏览器加载事件变化的时候执行unbindReady
            document.attachEvent('onreadystatechange',unbindReady);
            // 确保会执行
            window.attachEvent('onload',fireReadyEvent);
        }

        var toplevel = false; // 是否顶层对象

        try {
            toplevel = window.frameElement == null;
        } catch(e) {}

        if ( document.documentElement.doScroll && toplevel ) {
            // IE通过判断doScroll,在onreadystatechange = 'complete' 之前执行
            doScrollCheck();
        }
    }

    function doScrollCheck() {
        if ( isFire ) {
            return;
        }

        try {
            // IE下加载BODY后即可正常执行doScroll()
            document.documentElement.doScroll("left");
        } catch( error ) {
            // 循环执行doScroll
            setTimeout( doScrollCheck, 1 );
            return;
        }

        // doScroll成功后执行队列
        fireReadyEvent();
    }

    // 移除绑定事件并执行队列
    function unbindReady(){
        if(document.addEventListener){
            //标准浏览器支持DOMContentLoaded事件
            document.removeEventListener('DOMContentLoaded',unbindReady,false);
            fireReadyEvent();
        }else if(document.attachEvent){
            if(document.readyState === 'complete'){
                // IE浏览器支持complete事件
                document.detachEvent('onreadystatechange',unbindReady);
                fireReadyEvent();
            }
        }
    }

    bindReady();
    window.onload = function(){
        console.log('LOAD加载完毕!');
    }

    addReadyEvent(function(){
        console.log('DOM加载完毕1!');
    });
    addReadyEvent(function(){
        console.log('DOM加载完毕22!');
    })
    addReadyEvent(function(){
        console.log('DOM加载完毕33!');
    })