用纯原生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]; } } } } }