位置:海鸟网 > IT > JavaScript >

即拷即用:onDOMReady(在DOM树载入后执行)

代码提取自jQuery.ready,先说明一下,为什么要提取jQuery的ready方法?

  因为在很多时候大家做前端时,需要在DOM树载入时马上执行一些函数,比如对导航条进行初始化。但又不愿意仅为了这一个需求而引入整个jQuery库,于是就把jQuery的ready方法提取出来,单独使用了。

  另外您也可以在构建自己的js框架时使用此函数。

  重复一遍,我们的口号是什么?彪悍的应用,没有一行代码是多余的!

  代码如下:

(function(){
       var isReady=false;//判断onDOMReady方法是否已经被执行过
       var readyList= [];//把需要执行的方法先暂存在这个数组里
       var timer;//定时器句柄
       ready=function(fn) {
              if (isReady )
                     fn.call( document);
              else
                     readyList.push( function() { return fn.call(this);});
              return this;
       }
       var onDOMReady=function(){
              for(var i=0;i<readyList.length;i++){
                     readyList[i].apply(document);
              }
              readyList = null;
       }
       var bindReady = function(evt){
              if(isReady) return;
              isReady=true;
              onDOMReady.call(window);
              if(document.removeEventListener){
                     document.removeEventListener("DOMContentLoaded", bindReady, false);
              }else if(document.attachEvent){
                     document.detachEvent("onreadystatechange", bindReady);
                     if(window == window.top){
                            clearInterval(timer);
                            timer = null;
                     }
              }
       };
       if(document.addEventListener){
              document.addEventListener("DOMContentLoaded", bindReady, false);
       }else if(document.attachEvent){
              document.attachEvent("onreadystatechange", function(){
                     if((/loaded|complete/).test(document.readyState))
                            bindReady();
              });
              if(window == window.top){
                     timer = setInterval(function(){
                            try{
                                   isReady||document.documentElement.doScroll('left');//在IE下用能否执行doScroll判断dom是否加载完毕
                            }catch(e){
                                   return;
                            }
                            bindReady();
                     },5);
              }
       }
})();



  使用方式类下:

ready(navInit);//navInit为已存在的函数



  或:

ready(function(){
       if(agt.toLowerCase().indexOf("msie 6") != -1)
              navInitForIE6();//如果浏览器是IE6,则执行navInitForIE6函数来初始化下拉菜单
});



  说明:

  当我们想在页面加载之后执行某个函数,肯定会想到onload了。但onload在浏览器看来,就是页面上的东西(img、iframe等资源)全部都加载完毕后才能发生,如果页面内有大的图片的话,会在页面展现后好久时间后才执行。如果只需要对DOM进行操作,那么这时就没必要等到页面全部加载了。我们需要更快的方法。

  Firefox有DOMContentLoaded事件可以轻松解决,可惜的就是IE没有。

  MSDN关于JSCRIPT的一个方法有段不起眼的话,当页面DOM未加载完成时,调用doScroll方法时,会产生异常。那么我们反过来用,如果不异常,那么就是页面DOM加载完毕了!

  这个函数Diego Perini在07年就发布了,方法名为IEContentLoaded,而且获得了广泛认同,以至于现在许多开源框架都是借鉴这种方法,譬如JQuery中的ready,在注释里有明确说明是有借鉴Diego Perini的IEContentLoaded方法。

  所以:对于Mozilla & Opera 浏览器,在DOM树载入后有现成的DOMContentLoaded事件;对于Safari浏览器,有document.onreadystatechange事件,当该事件触发时,如果document.readyState=complete时,可视为dom树已经载入;对于IE,当在iframe内时,同样有document.onreadystatechange事件;对于IE在非iframe内时,只有不断地通过能否执行doScroll判断dom是否加载完毕。在本例中每间隔5毫秒尝试去执行document.documentElement.doScroll('left')。

  另外要注意一点:在IE8下,貌视非iframe窗口也会有document.onreadystatechange事件。