jQuery实现domReady和onload判断及兼容的方法

对于 jQuery 使用中 $( function(){} ) 的形式我们都不陌生,将事件函数绑定在 dom 加载完毕的时刻,相对于 window.onload 来讲可以避免一些图片,动态脚本,以及一些外部资源等加载对于当前代码执行带来的较大的延时影响,因为 window.onload 是需要等当前页面需要加载的资源全部加载结束后才触发执行,包括 onload 触发之前执行的动态加载。

对于标准浏览器,具有 DOMContentLoaded 事件来作为 dom 加载完毕后触发的事件,当然准确点说的话是 dom 和 非动态加载的JS 加载完毕时刻触发(关于触发时机可以看这里 JS、CSS以及img对DOMContentLoaded 事件的影响)。
   
当然低版本的IE(IE6 ~ IE8)不支持 DOMContentLoaded 事件,那么也需要使用一些其他的方法来进行模拟 DOMContentLoaded 时刻触发。当前主流的低版本IE模拟方法就是使用 doScroll 进行循环判断,对于 JScript ,若在 dom 未加载完毕时刻调用 doScroll 则会报错,借此使用 try catch 进行轮询判定。

那么,要了解 jQuery 对 domReady 和 load 的区分,其实就是说 jQuery 对于兼用的 domReady 是如何实现的而已,因为 onload 是各个浏览器已经实现的事件,而 DOMContentLoaded 未被低版本IE实现。然后本次使用的 jQuery 版本为 1.11,毕竟还要包括以下低版本IE,所以不使用 2.*的版本,但其实质是一样的,只不过 2.*版本中就舍弃使用 doScroll 进行循环判定放弃低版本IE而已。那么,要了解本质,最好的办法还是看 jQuery 源码。

 代码如下 复制代码

// DOM ready 的 一个 jQuery deferred
// 也作为 绑定初始化的判定标签
var readyList;

// 调用绑定才进行 绑定初始化
jQuery.fn.ready = function( fn ) {
    // 未初始化过的才进行初始化绑定
    jQuery.ready.promise().done( fn );
    return this;
};

jQuery.extend({
    // DOM ready 是否触发过标签
    isReady: false,
    readyWait: 1,

    holdReady: function( hold ) {
        if ( hold ) {
            jQuery.readyWait++;
        } else {
            jQuery.ready( true );
        }
    },

    // DOM ready 时刻的事件句柄
    ready: function( wait ) {

        if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {
            return;
        }

        // IE的小BUG 确保 body 已经存在
        if ( !document.body ) {
            return setTimeout( jQuery.ready );
        }

        // 切换标签状态
        jQuery.isReady = true;

        // 是否需要等待的标签
        if ( wait !== true && --jQuery.readyWait > 0 ) {
            return;
        }

        // 执行以 jquery 形式的 ready 绑定
        readyList.resolveWith( document, [ jQuery ] );

        // 在次触发其他形式的绑定,并且及时注销
        if ( jQuery.fn.triggerHandler ) {
            jQuery( document ).triggerHandler( "ready" );
            jQuery( document ).off( "ready" );
        }
    }
});

扩展的 isReady 是用来控制 ready 的执行次数的,readyWait 和 holdReady 在此不在此文解释范围,其中的 ready 方法 就是核心了,为 jQuery 判定 domReady 时所触发的方法,又结合了 defferred 的 resolveWith 逐一执行存储在 cache 中事件句柄数组中的事件句柄。那么接下来就是 domReady 的重头戏,判定 domReady 时刻。

 代码如下 复制代码
// 移除所有有关事件句柄 compeleted 的绑定事件
function detach() {
    if ( document.addEventListener ) {
        document.removeEventListener( "DOMContentLoaded", completed, false );
        window.removeEventListener( "load", completed, false );
    } else {
        document.detachEvent( "onreadystatechange", completed );
        window.detachEvent( "onload", completed );
    }
}

// 对于已经过了 domReady 时间点
function completed() {
    // 标准浏览器 或者 为 IE下的load事件 或者 ready 状态为 complete(IE)
    if ( document.addEventListener || event.type === "load" || document.readyState === "complete" ) {
        detach();
        jQuery.ready();
    }
}

jQuery.ready.promise = function( obj ) {
    if ( !readyList ) {
        // 初始化 readyList
        readyList = jQuery.Deferred();

        // 当 $(document).ready() 早在 ready 事件过后被调用的时候,直接触发。
        if ( document.readyState === "complete" ) {
            // 异步方式执行 类似的模拟事件触发形式
            setTimeout( jQuery.ready );

            // DOMContentLoaded 事件绑定
        } else if ( document.addEventListener ) {
            document.addEventListener( "DOMContentLoaded", completed, false );
            window.addEventListener( "load", completed, false );

        // 这边则是低版本IE形式
        } else {
            document.attachEvent( "onreadystatechange", completed );
            window.attachEvent( "onload", completed );

            // IE的 doScroll 方式检测
            var top = false;

            try {
                top = window.frameElement == null && document.documentElement;
            } catch(e) {}

            if ( top && top.doScroll ) {
                (function doScrollCheck() {
                    if ( !jQuery.isReady ) {
                        try {
                            top.doScroll("left");
                        } catch(e) {
                            // 当try中有错误 直接下次延迟循环检测
                            return setTimeout( doScrollCheck, 50 );
                        }

                        detach();
                        jQuery.ready();
                    }
                })();
            }
        }
    }
    return readyList.promise( obj );
};

其实对于 jQuery 这种形式来说,有点类似于 宁可错杀一千,也不放过一个,在任何状态下尽可能的多监听些事件进行判断,在 DOMContentLoaded,load,readystatechange 以及 doScroll 循环等, 反正有 jQuery.isReady 进行把关么,怕什么。对于该流程进一步了解还需要去了解一下 jquery 的 promise。关于 jQuery 的 callback, defferred的作用和源码。为什么要返回  readyList.promise( obj ),自己思考下吧!

时间: 2024-10-22 17:53:59

jQuery实现domReady和onload判断及兼容的方法的相关文章

jQuery ready与window.onload用法理解

最近做一个项目,在上一篇文章里面写了一个插件:jQuery滚动固定插件,刚开始时在本地测试,发现都没问题,后来架设到服务器上,发现浮动的末位置总是不对,总以为是哪些代码冲突或者是插件写得不完善,后来开启了调试.发现那个底部Bottom参数的高度随着刷新浏览器在变化,不可能啊.元素是固定在那里的.没有想到是jQuery的原因. 以浏览器装载文档为例,页面加载完毕后,浏览器会通过Javascript为DOM元素添加事件,在常规的Javascript代码中,通常使用window.onload方法,而在

jQuery获取复选框被选中数量及判断选择值的方法详解_jquery

本文实例讲述了jQuery获取复选框被选中数量及判断选择值的方法.分享给大家供大家参考,具体如下: 获取复选框被选中值 <input type="button" id="btn5" value="获得选中的所有值"> <input type="text" name="dd" id="dd" size="50" /> $("#btn5&

jquery的deferred对象实现判断页面中所有图片加载完成

判断页面中所有图片是否加载完成 对于图片是否加载完成,我们平时可以用监听图片load 方法来进行.今天主要介绍用jquery的deferred对象来进行判断. 关于jquery的deferred对象,是jquery的重点和难点.对于执行较长时间的函数,我们通常用deferred对象.关于jquery的deferred对象的API请看http://api.jquery.com/category/deferred-object/ 对于deferred对象,大家可以看下阮一峰写的一篇文章jQuery的

jQuery基于$.ajax设置移动端click超时处理方法_jquery

本文实例讲述了jQuery基于$.ajax设置移动端click超时处理方法.分享给大家供大家参考,具体如下: 这里介绍jquery click事件如何在移动端自动转换成touchstart事件. 因为移动端click事件会比touchstart事件慢几拍 移动设备某个元素上事件执行顺序是: touchstart touchmove touchend click{mousedown->mousemove->mouseup} click事件在移动设备上虽然会识别但却是最后一个执行的,所以如果不把c

jQuery实现Div拖动+键盘控制综合效果的方法

 这篇文章主要介绍了jQuery实现Div拖动+键盘控制综合效果的方法,实例分析了jQuery操作div块拖动的技巧,具有一定参考借鉴价值,需要的朋友可以参考下     本文实例讲述了jQuery实现Div拖动+键盘控制综合效果的方法.分享给大家供大家参考.具体实现方法如下:   代码如下: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml

JQuery鼠标移到小图显示大图效果的方法_jquery

本文实例讲述了JQuery鼠标移到小图显示大图效果的方法.分享给大家供大家参考.具体分析如下: 这里的显示大图功能类似上一篇<JQuery实现超链接鼠标提示效果的方法>,稍微修改一下代码,就可以做出一个图片的提示效果. 参考前面的超链接提示效果的代码,只需要将创建的div元素的代码改为: //创建 div 元素 图片提示 var tooltip = "<div id="tooltip"><img src=""+ this.hr

jquery基本选择器匹配多个元素的实现方法_jquery

如下所示: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title> new document &

3kb jQuery代码搞定各种树形选择的实现方法_jquery

自制Jquery树形选择插件. 对付各种树形选择(省市,分类..)90行Jquery代码搞定,少说废话直接上插件代码.稍后介绍使用说明.是之前写的一个插件的精简版. 1.Jquery插件代码 (function (j) { j.fn.attrs = function (option) { var root = this, data = []; //默认参数 var def = { url: '/ajax/GetSort/', str: root.attr("str") || '0',

使用JQuery 加载页面时调用JS的实现方法_jquery

1,window.onload = function() {}; 2,$(document).ready(function() {}); 一.一般的加载页面时调用js方法如下: window.onload = function() { $("table tr:nth-child(even)").addClass("even"); //这个是jquery代码 }; 这段代码会在整个页面的document全部加载完成以后执行.不幸的这种方式不仅要求页面的DOM tree