dom ready方法 - 从jQuery中剥离的独立方法

熟悉jQuery的都知道 $(function(){/*一些操作*/}); 和 $(document).ready(function(){/*一些操作*/}); ,

这里剥离出里面的dom ready方法,以便应用在一些不必使用jQuery等较大框架的页面中,顺便学习分享下jQuery内部代码。

该代码中dom ready的两个基本原理:

  1. 在webkit、mozilla、opera、IE9+中,支持DOMContentLoaded事件(IE9开始支持addEventListener等标准事件函数);
  2. 在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);

调用示例:

View Code
<!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>

 

posted @ 2012-07-23 16:22  隐火  阅读(1501)  评论(4编辑  收藏  举报