模擬jQuery中的ready方法及實(shí)現(xiàn)按需加載css,js實(shí)例代碼
一、ready函數(shù)的實(shí)現(xiàn)經(jīng)常用jQuery類(lèi)庫(kù)或其他類(lèi)庫(kù)中的ready方法,有時(shí)候想想它們到底是怎么實(shí)現(xiàn)的,但是看了一下jQuery中的源碼,涉及到的模塊比較多,(水平有限)代碼比較難看懂;自己結(jié)合了一些書(shū)籍內(nèi)容,總結(jié)一下。
先說(shuō)一下ready函數(shù)的實(shí)現(xiàn)思路:
變量ready通過(guò)表達(dá)式賦值,右側(cè)為一個(gè)自執(zhí)行匿名函數(shù),在這個(gè)匿名函數(shù)中,首先為各個(gè)瀏覽器的事件綁定處理函數(shù),并為isReady賦值(根據(jù)事件異步處理程序來(lái)確定),然后返回一個(gè)傳參閉包,在閉包中,主要判斷isReady值來(lái)執(zhí)行操作,如果dom結(jié)構(gòu)準(zhǔn)備就緒(isReady === true),執(zhí)行回調(diào),否則將回調(diào)加入到要執(zhí)行的隊(duì)列(funs)中,待事件處理程序執(zhí)行時(shí),循環(huán)遍歷隊(duì)列(funs),并依次執(zhí)行隊(duì)列中的函數(shù),執(zhí)行完隊(duì)列中的函數(shù)后,還需要清除隊(duì)列(funs = null)。
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:
該函數(shù)代碼參照于權(quán)威指南書(shū)籍,唯一不同的是,多加了一個(gè)判斷document.readyState !== 'interactive'
if ( e.type === 'readystatechange' && (document.readyState !== 'interactive' && document.readyState !== 'complete') ) {
return;
}
在各個(gè)瀏覽器中交互和完成狀態(tài)出現(xiàn)順序并不能保證一致,這取決于瀏覽器及頁(yè)面的內(nèi)容,多加了這個(gè)判斷document.readyState !== 'interactive'的話,
意思是不管哪個(gè)階段先出現(xiàn),代碼都能更早的執(zhí)行。
二、按需加載css,js
參照了jQuery源碼,寫(xiě)了一個(gè)type函數(shù),返回參數(shù)類(lèi)型。
/**
*
* 判斷參數(shù)類(lèi)型
* 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執(zhí)行兩次
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執(zhí)行兩次
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: 在判斷l(xiāng)ink,script元素是否加載完畢,主要依靠load事件;而在ie9以下瀏覽器中,并沒(méi)有l(wèi)oad事件,ie為它們都添加了一個(gè)readystatechange事件,通過(guò)判斷
元素的readyState狀態(tài)確定元素是否已經(jīng)加載完畢;而奇怪的是,在ie9(還可能存在其他瀏覽器版本)中,元素既有l(wèi)oad事件又有readystatechange事件,因此在代碼中添加了一個(gè)變量isExecuted,如果執(zhí)行過(guò)回調(diào),那么就不再執(zhí)行,避免回調(diào)執(zhí)行兩次。
三、調(diào)用方式
loadCss('//www.dbjr.com.cn/apps/tbtx/miiee/css/base.css', function(){
console.log('css加載完畢');
});
loadScript('//www.dbjr.com.cn/apps/tbtx/miiee/js/jQuery.js', function(){
console.log('js加載完畢');
});
ready(function(){
console.log('dom is ready!');
});
相關(guān)文章
jquery validate添加自定義驗(yàn)證規(guī)則(驗(yàn)證郵箱 郵政編碼)
這篇文章主要介紹了query validate添加自定義驗(yàn)證規(guī)則,可以驗(yàn)證郵箱、郵政編碼等,看代碼參考使用2013-12-12jQuery方法簡(jiǎn)潔實(shí)現(xiàn)隔行換色及toggleClass的使用
隔行換色的展示效果想必大家早已熟悉了吧,今天在幫大家回憶一下本例中主要用到的方法是toggleClass(),感興趣的你可不要錯(cuò)過(guò)了哈,希望可以幫助到你2013-03-03JQuery Ajax WebService傳遞參數(shù)的簡(jiǎn)單實(shí)例
下面小編就為大家?guī)?lái)一篇JQuery Ajax WebService傳遞參數(shù)的簡(jiǎn)單實(shí)例。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-11-11jquery實(shí)現(xiàn)通用版鼠標(biāo)經(jīng)過(guò)淡入淡出效果
這篇文章主要介紹了jquery實(shí)現(xiàn)的通用版鼠標(biāo)經(jīng)過(guò)淡入淡出效果,需要的朋友可以參考下2014-06-06關(guān)于Jquery中的bind(),on()綁定事件方式總結(jié)
下面小編就為大家?guī)?lái)一篇關(guān)于Jquery中的bind(),on()綁定事件方式總結(jié)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-10-10jquery ajax請(qǐng)求方式與提示用戶(hù)正在處理請(qǐng)稍等
為了提高用戶(hù)體驗(yàn)度,我們通常會(huì)給出 “正在處理,請(qǐng)稍等!”諸如此類(lèi)的提示。我們可通過(guò)設(shè)置$.ajax()下的參數(shù)beforeSend()來(lái)實(shí)現(xiàn)2014-09-09jQuery實(shí)現(xiàn)簡(jiǎn)單全選框
這篇文章主要為大家詳細(xì)介紹了jQuery實(shí)現(xiàn)簡(jiǎn)單全選框,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-09-09