聲明:這一篇文章是轉載過來的,轉載地址忘記了,原做者若是看到了,但願可以告知一聲,我好加上去!javascript
easyloader模塊是用來加載jquery easyui的js和css文件的,並且它能夠分析模塊的依賴關係,先加載依賴項。模塊加載好了會調用parse模塊來解析頁面。把class是easyui開頭的標籤都轉化成easyui的控件。css
先看Demo1例子,再分析源代碼。html
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <title>easyloader範例</title> 5 <meta http-equiv="content-type" content="text/html; charset=UTF-8"> 6 <!-- 引入JQuery --> 7 <script type="text/javascript" src="jquery-easyui-1.4.1/jquery.min.js"></script> 8 <!-- 引入easyloader.js --> 9 <script type="text/javascript" src="jquery-easyui-1.4.1/easyloader.js"></script> 10 </head> 11 12 <body> 13 <div class="easyui-panel" title="Demo1" fit="false" 14 collapsible="true" minimizable="true" maximizable="true" closable="true" style="width:100%; height: 200px;" > 15 easyloader會自動解析這個div,由於class屬性中帶有easyui開頭的類! 16 </div> 17 </body> 18 </html>
運行結果以下所示:java
easyloader源碼分析jquery
1 /** 2 * easyloader - jQuery EasyUI 3 * 4 * Licensed under the GPL: 5 * http://www.gnu.org/licenses/gpl.txt 6 * 7 * Copyright 2010 stworthy [ stworthy@gmail.com ] 8 * 9 */ 10 (function(){ 11 // 模塊文件定義 12 var modules = { 13 draggable:{ 14 js:'jquery.draggable.js' 15 }, 16 droppable:{ 17 js:'jquery.droppable.js' 18 }, 19 resizable:{ 20 js:'jquery.resizable.js' 21 }, 22 linkbutton:{ 23 js:'jquery.linkbutton.js', 24 css:'linkbutton.css' 25 }, 26 pagination:{ 27 js:'jquery.pagination.js', 28 css:'pagination.css', 29 dependencies:['linkbutton'] 30 }, 31 datagrid:{ 32 js:'jquery.datagrid.js', 33 css:'datagrid.css', 34 dependencies:['panel','resizable','linkbutton','pagination'] 35 }, 36 treegrid:{ 37 js:'jquery.treegrid.js', 38 css:'tree.css', 39 dependencies:['datagrid'] 40 }, 41 panel: { 42 js:'jquery.panel.js', 43 css:'panel.css' 44 }, 45 window:{ 46 js:'jquery.window.js', 47 css:'window.css', 48 dependencies:['resizable','draggable','panel'] 49 }, 50 dialog:{ 51 js:'jquery.dialog.js', 52 css:'dialog.css', 53 dependencies:['linkbutton','window'] 54 }, 55 messager:{ 56 js:'jquery.messager.js', 57 css:'messager.css', 58 dependencies:['linkbutton','window'] 59 }, 60 layout:{ 61 js:'jquery.layout.js', 62 css:'layout.css', 63 dependencies:['resizable','panel'] 64 }, 65 form:{ 66 js:'jquery.form.js' 67 }, 68 menu:{ 69 js:'jquery.menu.js', 70 css:'menu.css' 71 }, 72 tabs:{ 73 js:'jquery.tabs.js', 74 css:'tabs.css', 75 dependencies:['panel','linkbutton'] 76 }, 77 splitbutton:{ 78 js:'jquery.splitbutton.js', 79 css:'splitbutton.css', 80 dependencies:['linkbutton','menu'] 81 }, 82 menubutton:{ 83 js:'jquery.menubutton.js', 84 css:'menubutton.css', 85 dependencies:['linkbutton','menu'] 86 }, 87 accordion:{ 88 js:'jquery.accordion.js', 89 css:'accordion.css', 90 dependencies:['panel'] 91 }, 92 calendar:{ 93 js:'jquery.calendar.js', 94 css:'calendar.css' 95 }, 96 combo:{ 97 js:'jquery.combo.js', 98 css:'combo.css', 99 dependencies:['panel','validatebox'] 100 }, 101 combobox:{ 102 js:'jquery.combobox.js', 103 css:'combobox.css', 104 dependencies:['combo'] 105 }, 106 combotree:{ 107 js:'jquery.combotree.js', 108 dependencies:['combo','tree'] 109 }, 110 combogrid:{ 111 js:'jquery.combogrid.js', 112 dependencies:['combo','datagrid'] 113 }, 114 validatebox:{ 115 js:'jquery.validatebox.js', 116 css:'validatebox.css' 117 }, 118 numberbox:{ 119 js:'jquery.numberbox.js', 120 dependencies:['validatebox'] 121 }, 122 spinner:{ 123 js:'jquery.spinner.js', 124 css:'spinner.css', 125 dependencies:['validatebox'] 126 }, 127 numberspinner:{ 128 js:'jquery.numberspinner.js', 129 dependencies:['spinner','numberbox'] 130 }, 131 timespinner:{ 132 js:'jquery.timespinner.js', 133 dependencies:['spinner'] 134 }, 135 tree:{ 136 js:'jquery.tree.js', 137 css:'tree.css', 138 dependencies:['draggable','droppable'] 139 }, 140 datebox:{ 141 js:'jquery.datebox.js', 142 css:'datebox.css', 143 dependencies:['calendar','validatebox'] 144 }, 145 parser:{ 146 js:'jquery.parser.js' 147 } 148 }; 149 150 // 國際化資源文件 151 var locales = { 152 'af':'easyui-lang-af.js', 153 'bg':'easyui-lang-bg.js', 154 'ca':'easyui-lang-ca.js', 155 'cs':'easyui-lang-cs.js', 156 'da':'easyui-lang-da.js', 157 'de':'easyui-lang-de.js', 158 'en':'easyui-lang-en.js', 159 'fr':'easyui-lang-fr.js', 160 'nl':'easyui-lang-nl.js', 161 'zh_CN':'easyui-lang-zh_CN.js', 162 'zh_TW':'easyui-lang-zh_TW.js' 163 }; 164 165 // 加載隊列 166 var queues = {}; 167 168 /** 169 * 加載js文件函數,過程就是動態建立一個script標籤,而後添加到head標籤中去。 170 * 有一個問題是監聽了script標籤的兩個事件函數,一個是onload,另外一個是onreadystatechange,這個數要是針對IE和非IE瀏覽器準備的 171 * 萬惡的IE瀏覽器!!! 172 */ 173 function loadJs(url, callback){ 174 var done = false; 175 var script = document.createElement('script'); 176 script.type = 'text/javascript'; 177 script.language = 'javascript'; 178 script.src = url; 179 script.onload = script.onreadystatechange = function(){ 180 if (!done && (!script.readyState || script.readyState == 'loaded' || script.readyState == 'complete')){ 181 done = true; 182 script.onload = script.onreadystatechange = null; 183 if (callback){ 184 callback.call(script); 185 } 186 } 187 } 188 document.getElementsByTagName("head")[0].appendChild(script); 189 } 190 191 /** 192 * 執行js文件。就是把js文件加載進來,再remove掉 193 * @param url js的url 194 * @callback 回調函數,執行完js時會調用這個函數 195 */ 196 function runJs(url, callback){ 197 loadJs(url, function(){ 198 document.getElementsByTagName("head")[0].removeChild(this); 199 if (callback){ 200 callback(); 201 } 202 }); 203 } 204 205 /** 206 * 加載css文件。和加載js文件同樣,動態建立一個link標籤,而後追加到head標籤中去 207 * @param url css的url 208 * @param callback 回調函數,加載完成後調用此函數 209 */ 210 function loadCss(url, callback){ 211 var link = document.createElement('link'); 212 link.rel = 'stylesheet'; 213 link.type = 'text/css'; 214 link.media = 'screen'; 215 link.href = url; 216 document.getElementsByTagName('head')[0].appendChild(link); 217 if (callback){ 218 callback.call(link); 219 } 220 } 221 222 /** 223 * 加載單獨的一個模塊 224 */ 225 function loadSingle(name, callback){ 226 227 // 加載隊列存入該模塊名,並表示狀態爲loading。 228 queues[name] = 'loading'; 229 230 // 根據模塊名,取出該模塊定義 231 var module = modules[name]; 232 233 // js加載狀態 234 var jsStatus = 'loading'; 235 236 // css加載狀態,從這裏你就能夠看出easyloader.css就是一個開關變量,控制是否加載模塊相應的css文件 237 var cssStatus = (easyloader.css && module['css']) ? 'loading' : 'loaded'; 238 239 // 是css文件,就使用loadCss來加載之 240 if (easyloader.css && module['css']){ 241 if (/^http/i.test(module['css'])){ 242 var url = module['css']; 243 } else { 244 var url = easyloader.base + 'themes/' + easyloader.theme + '/' + module['css']; 245 } 246 loadCss(url, function(){ 247 cssStatus = 'loaded'; 248 if (jsStatus == 'loaded' && cssStatus == 'loaded'){ 249 finish(); 250 } 251 }); 252 } 253 254 // 是js文件,就是用LoadJs來加載之 255 if (/^http/i.test(module['js'])){ 256 var url = module['js']; 257 } else { 258 var url = easyloader.base + 'plugins/' + module['js']; 259 } 260 loadJs(url, function(){ 261 jsStatus = 'loaded'; 262 if (jsStatus == 'loaded' && cssStatus == 'loaded'){ 263 finish(); 264 } 265 }); 266 267 // 最終調用finish函數,來結束加載。並觸發onProgress函數,每加載成功一個模塊,就調用一次onProgress 268 function finish(){ 269 queues[name] = 'loaded'; 270 easyloader.onProgress(name); 271 if (callback){ 272 callback(); 273 } 274 } 275 } 276 277 /** 278 * easyui模塊加載函數 279 * @param name 模塊名,能夠是string,也能夠是數組 280 * @param callback 回調函數,當加載結束後會調用此函數 281 */ 282 function loadModule(name, callback){ 283 284 // 模塊名,根據依賴關係,從前到後,依次排開 285 var mm = []; 286 287 // 加載標識,當其值爲true時,表示須要加載的模塊已經加載好了 288 var doLoad = false; 289 290 // 模塊名支持兩中,一種是string,一種是數組。這樣就能夠一次加載多個模塊了 291 if (typeof name == 'string'){ 292 // 是string的時候,調用add方法把模塊名push到mm數組中去 293 add(name); 294 } else { 295 for(var i=0; i<name.length; i++){ 296 // 是數組的時候,循環調用add方法把模塊名通通push到mm數組中去 297 add(name[i]); 298 } 299 } 300 301 /** 302 * loadModule函數中內嵌的一個函數,用來加載模塊名到變量mm數組中去 303 * @param name 模塊名,只能是string 304 */ 305 function add(name){ 306 // 保護措施,若是該模塊名不存在,咱們就不要加載了 307 if (!modules[name]) return; 308 309 // 不然,就是該模塊存在。而後,咱們在看看其有沒有依賴模塊 310 var d = modules[name]['dependencies']; 311 if (d){ 312 // 若是有依賴模塊,咱們要先把依賴模塊的名字push到mm中去 313 // 這裏用了遞歸調用 314 for(var i=0; i<d.length; i++){ 315 add(d[i]); 316 } 317 } 318 319 // 把模塊名放到mm中 320 mm.push(name); 321 } 322 323 /** 324 * 當一個模塊及其依賴模塊加載完成時,執行回調函數,而且觸發onLoad函數 325 */ 326 function finish(){ 327 if (callback){ 328 callback(); 329 } 330 easyloader.onLoad(name); 331 } 332 333 // 加載用時 334 var time = 0; 335 336 /** 337 * 加載所須要的模塊,須要的模塊,咱們已經統計好了,並按依賴關係,前後push到mm中去了 338 */ 339 function loadMm(){ 340 // 判斷mm是否是空的 341 if (mm.length){ 342 343 // 第一個模塊 344 var m = mm[0]; 345 346 // 判斷加載隊列是否包含此模塊 347 if (!queues[m]){ 348 349 // 加載隊列不包含此模塊,開始加載該模塊 350 // 把doLoad置成true,表示開始加載 351 doLoad = true; 352 353 // 調用loadSingle方法來加載模塊,加載成功後會把此模塊從mm中shift掉,而後繼續調用loadMM方法,就造成了遞歸調用 354 loadSingle(m, function(){ 355 mm.shift(); 356 loadMm(); 357 }); 358 } else if (queues[m] == 'loaded'){ 359 // 加載隊列已經加載過此模塊了,不須要在加載了,直接從mm中shift掉便可 360 mm.shift(); 361 loadMm(); 362 } else { 363 // 表示正在加載該模塊,累計所用時間若是沒有超過timeout 364 // 則過10毫秒再調用一次loadMm函數 365 if (time < easyloader.timeout){ 366 time += 10; 367 setTimeout(arguments.callee, 10); 368 } 369 } 370 } else { 371 // 走到這裏,表示該加載的模塊都已經加載好了 372 if (easyloader.locale && doLoad == true && locales[easyloader.locale]){ 373 // 若是設置了國際化,而且已經加載好了,並且該國際化資源還存在,那麼加載該資源js 374 var url = easyloader.base + 'locale/' + locales[easyloader.locale]; 375 376 // 執行js完過後,調用finish方法 377 runJs(url, function(){ 378 finish(); 379 }); 380 } else { 381 // 沒定義國際化文件,那麼直接調用finish方法吧 382 finish(); 383 } 384 } 385 } 386 387 loadMm(); 388 } 389 390 /** 391 * easyloader定義爲全局變量 392 */ 393 easyloader = { 394 395 // 各個模塊文件的定義,包括js、css和依賴模塊 396 modules:modules, 397 398 // 國際化資源文件 399 locales:locales, 400 401 // jquery-easyui的根目錄,在加載easyloader時,會自動根據你放置的位置而改變 402 base:'.', 403 404 // 控件的主題,一共就有兩個,在theme目錄中。還有一個gray主題,淺灰色的,很難看。 405 theme:'default', 406 407 // 這是一個開關變量,控制easyloader加載模塊時,要不要加載相應的css文件,默認是須要加載的 408 css:true, 409 410 // 國際化語言,能夠根據window.navigator.language或者window.navigator.userLanguage來獲取當前瀏覽器的語言。 411 // 有兩個屬性,主要由於IE瀏覽器只認識userLanguage和sysLanguage,萬惡的IE瀏覽器啊! 412 locale:null, 413 414 // 加載一個模塊的最長時間,超過這個時間,就開始加載下一個模塊了。 415 timeout:2000, 416 417 // easyloader就公開了這麼一個方法,用來加載模塊。 418 // name是模塊名,callback是加載成功後執行的函數 419 load: function(name, callback){ 420 if (//.css$/i.test(name)){ 421 // 若是模塊名是以.css結尾 422 423 if (/^http/i.test(name)){ 424 // 若是模塊名是以http開頭,那麼css是一個文件的url 425 loadCss(name, callback); 426 } else { 427 // 不然,說明模塊名相對於jquery easyui根目錄來講的 428 loadCss(easyloader.base + name, callback); 429 } 430 } else if (//.js$/i.test(name)){ 431 // 若是模塊名是以.js結尾 432 433 if (/^http/i.test(name)){ 434 // 若是模塊名是以http開頭,那麼js是一個文件的url 435 loadJs(name, callback); 436 } else { 437 // 不然,說明模塊名相對於jquery easyui根目錄來講的 438 loadJs(easyloader.base + name, callback); 439 } 440 } else { 441 // 以上兩種都不是,說明是easyui本身的模塊,直接使用loadModule來加載,就能夠了 442 loadModule(name, callback); 443 } 444 }, 445 446 // 當一個模塊加載完會觸發此函數 447 onProgress: function(name){}, 448 449 // 當一個模塊和其依賴都加載完會觸發此函數 450 onLoad: function(name){} 451 }; 452 /** 453 * 這一小段代碼就是查找jquery-easyui的根目錄,並賦值給easyloader的base屬性上。這樣easyloader再加載css文件和js文件就很方便定位了。 454 */ 455 var scripts = document.getElementsByTagName('script'); 456 for(var i=0; i<scripts.length; i++){ 457 var src = scripts[i].src; 458 if (!src) continue; 459 var m = src.match(/easyloader/.js(/W|$)/i); 460 if (m){ 461 easyloader.base = src.substring(0, m.index); 462 } 463 } 464 /** 465 * 這個就起一個別名的做用,好比頁面中能夠想以下這麼下: 466 * using('window'); 467 * 這樣window模塊就加載進來了! 468 */ 469 window.using = easyloader.load; 470 /** 471 * easyloader.js加載的第一模塊是parse模塊,parser模塊調用parse方法,能夠解析頁面上的easyui控件 472 */ 473 if (window.jQuery){ 474 jQuery(function(){ 475 easyloader.load('parser', function(){ 476 jQuery.parser.parse(); 477 }); 478 }); 479 } 480 481 })();
到這裏easyloader就分析結束了,若是你仔細看過了,相信必定會使用easyloader了數組