1 var //......代码省略 2 //事件回调函数列表对象 3 //为了便于解释暂且称之为ready事件回调函数列表对象, 4 //当然DOM事件模型是没有所谓的ready事件的哦。 5 readyList 6 //......代码省略 7 ; 8 jQuery.fn = jQuery.prototype = { 9 //......代码省略 10 ready: function( fn ) { 11 // Attach the listeners 12 // 绑定ready事件监听器,DOM标准里是无所谓ready事件, 13 // 这里只是自己起的为了方便分析代码 14 jQuery.bindReady(); 15 // Add the callback 16 // 添加回调函数到回调函数列表中 17 readyList.add( fn ); 18 return this; 19 }, 20 //......代码省略 21 }; 22 jQuery.extend({ 23 //......代码省略 24 // Is the DOM ready to be used? Set to true once it occurs. 25 // 标识页面DOM元素是否已加载完毕 26 isReady: false, 27 // A counter to track how many items to wait for before 28 // the ready event fires. See #6781 29 readyWait: 1, 30 // Hold (or release) the ready event 31 holdReady: function( hold ) { 32 if ( hold ) { 33 jQuery.readyWait++; 34 } else { 35 jQuery.ready( true ); 36 } 37 }, 38 // Handle when the DOM is ready 39 ready: function( wait ) { 40 // Either a released hold or an DOMready/load event and not yet ready 41 if ( (wait === true && !--jQuery.readyWait) || (wait !== true && !jQuery.isReady) ) { 42 // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). 43 if ( !document.body ) { 44 return setTimeout( jQuery.ready, 1 ); 45 } 46 // Remember that the DOM is ready 47 jQuery.isReady = true; 48 // If a normal DOM Ready event fired, decrement, and wait if need be 49 if ( wait !== true && --jQuery.readyWait > 0 ) { 50 return; 51 } 52 // If there are functions bound, to execute 53 readyList.fireWith( document, [ jQuery ] ); 54 // Trigger any bound ready events 55 if ( jQuery.fn.trigger ) { 56 jQuery( document ).trigger( "ready" ).off( "ready" ); 57 } 58 } 59 }, 60 bindReady: function() { 61 //判断ready事件回调函数列表是否已初始化 62 if ( readyList ) { 63 //如是则返回 64 return; 65 } 66 //创建ready事件回调函数列表对象 67 //这里调用jQuery.Callbacks方法, 68 //Callbacks的作用在上篇已说过,不再赘述 69 readyList = jQuery.Callbacks( "once memory" ); 70 // Catch cases where $(document).ready() is called after the 71 // browser event has already occurred. 72 // 判断页面DOM元素是否已加载完毕 73 if ( document.readyState === "complete" ) { 74 // Handle it asynchronously to allow scripts the opportunity to delay ready 75 // 如是则异步执行jQuery.ready方法 76 // 调用setTimeout目的是异步执行jQuery.ready方法 77 return setTimeout( jQuery.ready, 1 ); 78 } 79 // Mozilla, Opera and webkit nightlies currently support this event 80 // 支持W3C DOM标准的浏览器则用addEventListener绑定 81 if ( document.addEventListener ) { 82 // Use the handy event callback 83 // 支持W3C DOM标准的浏览器一般是支持DOMContentLoaded事件 84 // DOMContentLoaded是页面的DOM元素(仅仅只是DOM元素)全部加载完毕后触发 85 document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false ); 86 // A fallback to window.onload, that will always work 87 // 当然有些所谓支持W3C DOM标准的浏览器可能不支持DOMContentLoaded事件, 88 // 为了不被坑爹,在此得留一手,为确保万无一失,再绑定window的load事件, 89 // 因为window的load事件是所有浏览器都支持的,页面载入完成后是肯定会触发。 90 // 在这里说明一下DOMContentLoaded和load事件的区别: 91 // DOMContentLoaded事件是只要页面DOM元素全部加载完毕即触发 92 // window的load事件是页面的所有DOM元素以及全部资源(如图片/flash)加载完毕即触发 93 // 理论上,DOMContentLoaded要比window的load事件先触发 94 window.addEventListener( "load", jQuery.ready, false ); 95 } 96 // If IE event model is used 97 // 针对IE浏览器用attachEvent绑定事件 98 // 题外话:IE遵循自己的一套DOM事件模型,与W3C DOM事件模型有很大不同 99 // 故需特殊对待 100 else if ( document.attachEvent ) { 101 // ensure firing before onload, 102 // maybe late but safe also for iframes 103 // IE不支持DOMContentLoaded事件,但可使用onreadystatechange事件替代之 104 document.attachEvent( "onreadystatechange", DOMContentLoaded ); 105 // A fallback to window.onload, that will always work 106 // 为了避免被onreadystatechange事件坑爹,需留一手, 107 // 绑定window的onload事件,这是页面载入完成后一定会触发的。 108 window.attachEvent( "onload", jQuery.ready ); 109 // If IE and not a frame 110 // continually check to see if the document is ready 111 var toplevel = false; 112 try { 113 //使用window.frameElement判断是否是顶级页面 114 toplevel = window.frameElement == null; 115 } catch(e) { 116 //抛异常,则当做不是顶级页面处理 117 } 118 //document.documentElement.doScroll 119 //IE独有方法,模拟用户滚动条点击; 120 //用此法判断IE下的DOM元素是否加载完成 121 if ( document.documentElement.doScroll && toplevel ) { 122 doScrollCheck(); 123 } 124 } 125 } 126 //......代码省略 127 }); 128 //.....代码省略 129 // The DOM ready check for Internet Explorer 130 // 检测IE浏览器下的DOM元素是否加载完成 131 function doScrollCheck() { 132 //判断页面是否已加载完毕 133 //如是则无需再执行下面的检测代码 134 if ( jQuery.isReady ) { 135 return; 136 } 137 // 执行document.documentElement.doScroll方法 138 // 若抛异常,表示IE的DOM元素未加载完毕,则继续异步执行doScrollCheck检测 139 // 若不抛异常,表示IE的DOM元素加载完成,则将执行jQuery.ready方法 140 try { 141 // If IE is used, use the trick by Diego Perini 142 // http://javascript.nwbox.com/IEContentLoaded/ 143 document.documentElement.doScroll("left"); 144 } catch(e) { 145 setTimeout( doScrollCheck, 1 ); 146 return; 147 } 148 // and execute any waiting functions 149 // IE的DOM元素加载完成调用jQuery.ready方法 150 jQuery.ready(); 151 } 152 //.....代码省略 153 // Cleanup functions for the document ready method 154 //支持W3C DOM标准浏览器 155 if ( document.addEventListener ) { 156 //DOMContentLoaded事件回调函数实现 157 DOMContentLoaded = function() { 158 //移除DOMContentLoaded事件绑定 159 document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false ); 160 jQuery.ready(); 161 }; 162 } 163 //支持微软DOM标准浏览器 164 else if ( document.attachEvent ) { 165 //onreadystatechange事件回调函数实现 166 DOMContentLoaded = function() { 167 // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). 168 if ( document.readyState === "complete" ) { 169 //移除onreadystatechange事件绑定 170 document.detachEvent( "onreadystatechange", DOMContentLoaded ); 171 jQuery.ready(); 172 } 173 }; 174 } 175 //.....代码省略