有了seajs、requireJ這樣的模塊加載框架,一直想研究,今天先嘗試自己來寫一下簡單的加載功能,等了解后再去看大牛們的源碼,僅當作為自己學習練習,有很多考慮不周的地方請指出,主要就兩個方法: VM.define(‘模塊名稱’,{url:‘模塊路徑’,requires:‘模塊依賴項’(可以是模塊名的字符串,或者數組)}); VM.use(‘模塊名稱’,‘回調函數callback’); 一個是定義模塊,一個是使用模塊;使用的模塊都必須先定義, 定義的時候不會加載模塊,只有在使用的時候才加載模塊; 1、不會出現重復加載的模塊,調用過的模塊不會再append第二次,不能定義相同名字的模塊; 2、依賴項可以是多個,從左到右加載,多個的時候用數組傳參,單個時可以用字符串傳參; 3、支持鏈式調用,要避免循環(huán)依賴的情況; 修改:上次的代碼存在考慮不周的情況,多謝園友 程序猿小卡 留言的指出,現再的也可能有問題,但是如果正常使用依賴,相信還是能夠滿足的,僅供研究:) 代碼如下:使用方法:只需引入myModule.js文件, <script type="text/javascript" src="myModule.js"></script> myModule.js代碼如下: 1 /** 2 3 * Author : vvg 4 5 * version : 0.1.1 6 7 * name : VModule.js 8 9 **/ 10 11 (function () { 12 // 調試提示 13 var log = function (content) { 14 if (typeof console.log === 'function') { 15 console.log(content); 16 } else { 17 alert(content); 18 } 19 } 20 21 var createScript = function (url) { 22 var script = document.createElement('script'); 23 script.type = 'text/javascript'; 24 script.src = url; 25 return script; 26 }; 27 28 var head = document.getElementsByTagName('head')[0]; 29 var toString = Object.prototype.toString; 30 31 var VModule = {}; 32 /** 33 * 定義模塊 34 * @param name {string} 35 * @param options {object} url/requires 36 */ 37 VModule.define = function (name, options) { 38 //定義模塊名稱、地址和依賴 39 if (!this.modules) this.modules = {}; 40 if (this.modules[name]) { 41 log(name + '已經存在,請更換名稱.'); 42 return; 43 } 44 this.modules[name] = options; 45 // 是否加載 46 this.modules[name].isLoad = false; 47 // 是否使用 48 this.modules[name].isUse = false; 49 // 回調隊列 50 this.modules[name].callBackQueue = []; 51 return this; 52 } 53 54 VModule.use = function (name, func) { 55 var len, self = this; 56 if (!this.modules[name]) { 57 log(name + '不存在.'); 58 return this; 59 } 60 // 回調隊列,用于多次use同一個模塊時的多個回調 61 var callBackQueue = this.modules[name].callBackQueue; 62 if (!this.modules[name].isUse) { 63 // 標記模塊已經使用過 64 this.modules[name].isUse = true; 65 // 推入隊列 66 callBackQueue.push(func); 67 var url = this.modules[name].url; 68 var requires = this.modules[name].requires; 69 70 // 串行依賴情況 71 if (toString.call(requires) == '[object String]') { 72 this.use(requires, function () { 73 self.load(name, callBackQueue); 74 }); 75 return this; 76 } 77 78 // 并行依賴處理 79 if (toString.call(requires) == '[object Array]') { 80 //循環(huán)查找 81 len = requires.length; 82 this.modules[name].count = len; 83 for (var i = 0; i < len; i++) { 84 var self = this; 85 this.use(requires[i], function () { 86 VModule.modules[name].count--; 87 // 串行依賴即等待所有的文件加載完畢后才執(zhí)行回調 88 if (VModule.modules[name].count == 0) { 89 self.load(name,callBackQueue); 90 } 91 }) 92 } 93 return this; 94 } 95 this.load(name, callBackQueue); 96 } else { 97 // 如果模塊已經標記使用,但是模塊還未下載完畢時,加入隊列, 如果下載完畢則直接執(zhí)行回調函數 98 if(!this.modules[name].isLoad){ 99 func && callBackQueue.push(func); 100 }else{ 101 func && func(); 102 } 103 return this; 104 } 105 } 106 VModule.load = function (name, callBackQueue) { 107 if (!this.modules[name].isLoad) { 108 var self = this; 109 var script = createScript(self.modules[name].url); 110 script.onload = script.onreadystatechange = function () { 111 if ((!this.readyState) || this.readyState === "loaded" || this.readyState === "complete") { 112 self.modules[name].isLoad = true; 113 // 循環(huán)調用回調隊列 114 for(var i = 0, n = callBackQueue.length;i<n;i++){ 115 callBackQueue[i](); 116 } 117 } 118 } 119 head.appendChild(script); 120 } 121 } 122 123 window.VM = VModule; 124 125 })(); 我的測試DEMO: <!DOCTYPE html> <html> <head> <meta charset="utf-8"/> <title>js模塊化</title> <script type="text/javascript" src="Module.js"></script> </head> <body> <p id="jq">測試</p> <p id="jq2">測試</p> <script type="text/javascript"> VM.define('a', {url:'moduleA.js', requires:['b', 'd', 'c']}) .define('b', {url:'moduleB.js'}) .define('c', {url:'http://common.cnblogs.com/script/jquery.js?178979879891'}) .define('d', {url:'moduleD.js', requires:['e', 'g', 'f']}) .define('e', {url:'moduleE.js', requires:'f'}) .define('f', {url:'moduleF.js'}).define('g', {url:'moduleG.js'}); VM.use('a', function () { $('#jq').html('JQ下載成功??!').css('color', 'red'); }).use('a', function () { $('#jq2').html('JQ下載成功!!').css('color', 'red'); }).use('a',function(){ $('#jq2').append('<em>第三次加載</em>').find('em').css('color','blue'); }).use('f',function(){ console.log('F加載成功!'); }) </script> </body> </html> DEMO下載地址:點我點我點我 |
|