用纯原生js实现jquery的ready函数(两种实现)

第一种实现方式:

var dom = new function() {
  var dom = [];
  dom.isReady = false;
  dom.isFunction = function(obj) {
    return Object.prototype.toString.call(obj) === "[object Function]";
  }
  
  //先会执行下面的分支函数,然后执行dom.initReady()函数,因为要等到DOM建完后才会执行
  dom.Ready = function(fn) {
    dom.initReady();//如果没有建成DOM树,则走第二步,存储起来一起杀
    if(dom.isFunction(fn)) {
      if(dom.isReady) {
        fn();//如果已经建成DOM,则来一个杀一个
      } else {
        dom.push(fn);//存储加载事件
      }
    }
  }
  dom.fireReady = function() {
    if (dom.isReady)  return;
    dom.isReady = true;
    for(var i=0, n=dom.length; i<n; i++) {
      dom[i]();
    }
    dom.length = 0;//清空事件
  }
  dom.initReady = function() {
    if (document.addEventListener) {
      document.addEventListener( "DOMContentLoaded", function() {
        document.removeEventListener( "DOMContentLoaded", arguments.callee, false );//清除加载函数
        dom.fireReady();
      }, false );
    } else {
      if (document.getElementById) {
        document.write("<script id=\"ie-domReady\" defer='defer'src=\"//:\"><\/script>");
        document.getElementById("ie-domReady").onreadystatechange = function() {
          if (this.readyState === "complete") {
            dom.fireReady();
            this.onreadystatechange = null;
            this.parentNode.removeChild(this)
          }
        };
      }
    }
  }
  return dom;
}

 

第二种实现方式

//浏览器检测
(function () {
    window.sys = {};
    var ua = navigator.userAgent.toLowerCase();    
    var s;        
    (s = ua.match(/msie ([\d.]+)/)) ? sys.ie = s[1] :
    (s = ua.match(/firefox\/([\d.]+)/)) ? sys.firefox = s[1] :
    (s = ua.match(/chrome\/([\d.]+)/)) ? sys.chrome = s[1] : 
    (s = ua.match(/opera\/.*version\/([\d.]+)/)) ? sys.opera = s[1] : 
    (s = ua.match(/version\/([\d.]+).*safari/)) ? sys.safari = s[1] : 0;
    
    if (/webkit/.test(ua)) sys.webkit = ua.match(/webkit\/([\d.]+)/)[1];
})();

//DOM加载
function Ready(fn) {
    var isReady = false;
    var timer = null;
    function doReady() {
        if (timer) clearInterval(timer);
        if (isReady) return;
        isReady = true;
        fn();
    }
    
    if ((sys.opera && sys.opera < 9) || (sys.firefox && sys.firefox < 3) || (sys.webkit && sys.webkit < 525)) {
        timer = setInterval(function () {
            if (document && document.getElementById && document.getElementsByTagName && document.body) {
                doReady();
            }
        }, 1);
    } else if (document.addEventListener) {//W3C
        addEvent(document, 'DOMContentLoaded', function () {
            fn();
            removeEvent(document, 'DOMContentLoaded', arguments.callee);
        });
    } else if (sys.ie && sys.ie < 9){
        var timer = null;
        timer = setInterval(function () {
            try {
                document.documentElement.doScroll('left');
                doReady();
            } catch (e) {};
        }, 1);
    }
}

 

当然上面的Ready函数需要依赖addEvent和removeEvent函数,这两个函数是经过兼容处理的函数,兼容所有浏览器,无任何bug,代码:

//跨浏览器添加事件绑定
function addEvent(obj, type, fn) {
    if (typeof obj.addEventListener != 'undefined') {
        obj.addEventListener(type, fn, false);
    } else {
        //创建一个存放事件的哈希表(散列表)
        if (!obj.events) obj.events = {};
        //第一次执行时执行
        if (!obj.events[type]) {    
            //创建一个存放事件处理函数的数组
            obj.events[type] = [];
            //把第一次的事件处理函数先储存到第一个位置上
            if (obj['on' + type]) obj.events[type][0] = fn;
        } else {
            //同一个注册函数进行屏蔽,不添加到计数器中
            if (addEvent.equal(obj.events[type], fn)) return false;
        }
        //从第二次开始我们用事件计数器来存储
        obj.events[type][addEvent.ID++] = fn;
        //执行事件处理函数
        obj['on' + type] = addEvent.exec;
    }
}

//为每个事件分配一个计数器
addEvent.ID = 1;

//执行事件处理函数
addEvent.exec = function (event) {
    var e = event || addEvent.fixEvent(window.event);
    var es = this.events[e.type];
    for (var i in es) {
        es[i].call(this, e);
    }
};

//同一个注册函数进行屏蔽
addEvent.equal = function (es, fn) {
    for (var i in es) {
        if (es[i] == fn) return true;
    }
    return false;
}

//把IE常用的Event对象配对到W3C中去
addEvent.fixEvent = function (event) {
    event.preventDefault = addEvent.fixEvent.preventDefault;
    event.stopPropagation = addEvent.fixEvent.stopPropagation;
    event.target = event.srcElement;
    return event;
};

//IE阻止默认行为
addEvent.fixEvent.preventDefault = function () {
    this.returnValue = false;
};

//IE取消冒泡
addEvent.fixEvent.stopPropagation = function () {
    this.cancelBubble = true;
};


//跨浏览器删除事件
function removeEvent(obj, type, fn) {
    if (typeof obj.removeEventListener != 'undefined') {
        obj.removeEventListener(type, fn, false);
    } else {
        if (obj.events) {
            for (var i in obj.events[type]) {
                if (obj.events[type][i] == fn) {
                    delete obj.events[type][i];
                }
            }
        }
    }
}

 

 

 

posted @ 2014-02-19 12:57  breezefeng  阅读(1367)  评论(0编辑  收藏  举报