dom ready方法 - 从jQuery中剥离的独立方法
熟悉jQuery的都知道 $(function(){/*一些操作*/}); 和 $(document).ready(function(){/*一些操作*/}); ,
这里剥离出里面的dom ready方法,以便应用在一些不必使用jQuery等较大框架的页面中,顺便学习分享下jQuery内部代码。
该代码中dom ready的两个基本原理:
- 在webkit、mozilla、opera、IE9+中,支持DOMContentLoaded事件(IE9开始支持addEventListener等标准事件函数);
- 在IE6/7/8中,首先监听onreadystatechange事件,判断document.readyState=="complete"模拟DOMContentLoaded事件,同时异步循环做doScroll检查。
另外,额外监听onload事件,确保在一些古老的浏览器里也能顺利执行。
代码如下:
1 /** 2 * 参考自 jQuery 1.7.2 3 */ 4 var domReady = (function(document){ 5 var // Is the DOM ready to be used? Set to true once it occurs. 6 isReady, 7 // The deferred used on DOM ready 8 readyList, 9 // The ready event handler 10 DOMContentLoaded; 11 12 function domReady(fn) { 13 bindReady(); 14 readyList.add(fn); 15 } 16 17 function bindReady() { 18 if (readyList) { 19 return; 20 } 21 readyList = Callbacks(); 22 23 // Catch cases where $(document).ready() is called after the 24 // browser event has already occurred. 25 if ( document.readyState === "complete" ) { 26 // Handle it asynchronously to allow scripts the opportunity to delay ready 27 return setTimeout( ready, 1 ); 28 } 29 30 // Mozilla, Opera and webkit nightlies currently support this event 31 if ( document.addEventListener ) { 32 // Use the handy event callback 33 document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false ); 34 35 // A fallback to window.onload, that will always work 36 window.addEventListener( "load", ready, false ); 37 38 // If IE event model is used 39 } else if ( document.attachEvent ) { 40 // ensure firing before onload, 41 // maybe late but safe also for iframes 42 document.attachEvent( "onreadystatechange", DOMContentLoaded ); 43 44 // A fallback to window.onload, that will always work 45 window.attachEvent( "onload", ready ); 46 47 // If IE and not a frame 48 // continually check to see if the document is ready 49 var toplevel = false; 50 51 try { 52 toplevel = window.frameElement == null; 53 } catch(e) {} 54 55 if ( document.documentElement.doScroll && toplevel ) { 56 doScrollCheck(); 57 } 58 } 59 } 60 61 // The DOM ready check for Internet Explorer 62 function doScrollCheck() { 63 if ( isReady ) { 64 return; 65 } 66 67 try { 68 // If IE is used, use the trick by Diego Perini 69 // http://javascript.nwbox.com/IEContentLoaded/ 70 document.documentElement.doScroll("left"); 71 } catch(e) { 72 setTimeout( doScrollCheck, 1 ); 73 return; 74 } 75 76 // and execute any waiting functions 77 ready(); 78 } 79 80 // Handle when the DOM is ready 81 function ready() { 82 if ( !isReady ) { 83 // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). 84 if ( !document.body ) { 85 return setTimeout( ready, 1 ); 86 } 87 88 // Remember that the DOM is ready 89 isReady = true; 90 91 readyList.fire(); 92 } 93 } 94 95 // Cleanup functions for the document ready method 96 if ( document.addEventListener ) { 97 DOMContentLoaded = function() { 98 document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false ); 99 ready(); 100 }; 101 102 } else if ( document.attachEvent ) { 103 DOMContentLoaded = function() { 104 // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). 105 if ( document.readyState === "complete" ) { 106 document.detachEvent( "onreadystatechange", DOMContentLoaded ); 107 ready(); 108 } 109 }; 110 } 111 112 function Callbacks() { 113 var // Actual callback list 114 list = [], 115 // Flag to know if list was already fired 116 fired, 117 // Flag to know if list is currently firing 118 firing, 119 // First callback to fire (used internally by add and fireWith) 120 firingStart, 121 // End of the loop when firing 122 firingLength, 123 // Index of currently firing callback (modified by remove if needed) 124 firingIndex; 125 126 var self = { 127 add: function(fn) { 128 var length = list.length; 129 list.push( fn ); 130 // Do we need to add the callbacks to the 131 // current firing batch? 132 if ( firing ) { 133 firingLength = list.length; 134 // With memory, if we're not firing then 135 // we should call right away, unless previous 136 // firing was halted (stopOnFalse) 137 } else if ( fired ) { 138 firingStart = length; 139 self.fire(); 140 } 141 }, 142 fire: function() { 143 fired = true; 144 firing = true; 145 firingIndex = firingStart || 0; 146 firingStart = 0; 147 firingLength = list.length; 148 for ( ; firingIndex < firingLength; firingIndex++ ) { 149 list[ firingIndex ].call( document ); 150 } 151 firing = false; 152 } 153 }; 154 return self; 155 } 156 157 return domReady; 158 })(window.document);
调用示例:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>test for dom ready</title> </head> <body> hehe <!-- domready.js --> <script src="./domready.js"></script> <script> domReady(function(){ alert('hello'); domReady(function(){ alert('world'); }); }); setTimeout(function(){ domReady(function(){ alert('soga'); domReady(function(){ alert('yoxi'); }); }); }, 2e3); </script> </body> </html>