zoukankan      html  css  js  c++  java
  • 用纯原生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];
                    }
                }
            }
        }
    }
  • 相关阅读:
    js对象,数组,字符串的操作
    js 类型之间的相互转化
    Spark常见问题汇总
    Spark RDD的默认分区数:(spark 2.1.0)
    手动合并hadoop namenode editlog
    Yarn参数优化(Fair Scheduler版本)
    linux中在某个目录下多个文件中搜索关键字
    JDK中jps、jinfo、jstat、jstack、jmap、jconsole等命令简介
    Elasticsearch 为何要在 7.X版本中 去除type 的概念
    Linux 查看内存使用情况
  • 原文地址:https://www.cnblogs.com/fengyuqing/p/javascript_ready.html
Copyright © 2011-2022 走看看