模拟jQuery中的ready方法及实现按需加载css,js实例代码 |
本文标签:jQuery,css,js 复制代码 代码如下: var ready = (function(){ var isReady = false, funs = []; function handle (e) { if ( isReady ) { return; } if ( e.type === readystatechange && (document.readyState !== interactive && document.readyState !== complete) ) { return; } for ( var i = 0; i < funs.length; i++ ) { funs[i].call(document); } isReady = true; funs = null; } if ( document.addEventListener ) { document.addEventListener( DOMContentLoaded, handle, false ); document.addEventListener( readystatechange, handle, false ); document.addEventListener( load, handle, false ); } else if ( document.attachEvent ) { document.attachEvent( onreadystatechange, handle ); document.attachEvent( onload, handle ); } return function ready (callback) { if ( isReady ) { callback.call(document); } else { funs.push(callback); } }; }()); PS: 该函数代码参照于权威指南书籍,唯一不同的是,多加了一个判断document.readyState !== interactive 复制代码 代码如下: if ( e.type === readystatechange && (document.readyState !== interactive && document.readyState !== complete) ) { return; } 在各个浏览器中交互和完成状态出现顺序并不能保证一致,这取决于浏览器及页面的内容,多加了这个判断document.readyState !== interactive的话, 意思是不管哪个阶段先出现,代码都能更早的执行 。 二、按需加载css,js 参照了jQuery源码,写了一个type函数,返回参数类型 。 复制代码 代码如下: /** * * 判断参数类型 * createTime: 2013/9/18 * */ function type (obj) { var classTypes, objectTypes; if ( obj == null ) { return String(obj); } classTypes = {}; objectTypes = (Boolean Number String Function Array Date RegExp Object Error).split( ); for ( var i = 0, len = objectTypes.length; i < len; i++ ) { classTypes[ [object + objectTypes[i] + ] ] = objectTypes[i].toLowerCase(); } if ( typeof obj === object || typeof obj === function ) { var key = Object.prototype.toString.call(obj); return classTypes[key]; } return typeof obj; } 复制代码 代码如下: // css按需加载 function loadCss (cssUrl, callback) { var elem, bl, isExecuted = false; // 防止在ie9中,callback执行两次 if ( cssUrl == null ) { return String(cssUrl); } elem = document.createElement(link), elem.rel = stylesheet; if ( type(callback) === function ) { bl = true; } // for ie function handle() { if ( elem.readyState === loaded || elem.readyState === complete ) { if (bl && !isExecuted) { callback(); isExecuted = true; } elem.onreadystatechange = null; } } elem.onreadystatechange = handle; // for 非ie if (bl && !isExecuted) { elem.onload = callback; isExecuted = true; } elem.href = cssUrl; document.getElementsByTagName(head)[0].appendChild(elem); } // js按需加载 function loadScript(scriptUrl, callback) { var elem, bl, isExecuted = false; // 防止在ie9中,callback执行两次 if (scriptUrl == null) { return String(fn); } elem = document.createElement(script); if ( type(callback) === function ) { bl = true; } // for ie function handle(){ var status = elem.readyState; if (status === loaded || status === complete) { if (bl && !isExecuted) { callback(); isExecuted = true; } elem.onreadystatechange = null; } } elem.onreadystatechange = handle; // for 非ie if (bl && !isExecuted) { elem.onload = callback; isExecuted = true; } elem.src = scriptUrl; document.getElementsByTagName(head)[0].appendChild(elem); } PS: 在判断link,script元素是否加载完毕,主要依靠load事件;而在ie9以下浏览器中,并没有load事件,ie为它们都添加了一个readystatechange事件,通过判断 元素的readyState状态确定元素是否已经加载完毕;而奇怪的是,在ie9(还可能存在其他浏览器版本)中,元素既有load事件又有readystatechange事件,因此在代码中添加了一个变量isExecuted,如果执行过回调,那么就不再执行,避免回调执行两次 。 三、调用方式 复制代码 代码如下: loadCss(http://www.jb51.net/apps/tbtx/miiee/css/base.css, function(){ console.log(css加载完毕); }); loadScript(http://www.jb51.net/apps/tbtx/miiee/js/jQuery.js, function(){ console.log(js加载完毕); }); ready(function(){ console.log(dom is ready!); }); |