posts - 495,comments - 227,trackbacks - 0
          http://www.cnblogs.com/lyzg/p/4865502.html

          通 過本文,你可以對模塊化開發和AMD規范有一個較直觀的認識,并詳細地學習RequireJS這個模塊化開發工具的常見用法。本文采取循序漸進的方式,從 理論到實踐,從RequireJS官方API文檔中,總結出在使用RequireJS過程中最常用的一些用法,并對文檔中不夠清晰具體的內容,加以例證和 分析,希望本文的內容對你的能力提升有實質性的幫助。

          1. 模塊化

          相信每個前端開發人員在剛開始接觸js編程時,都寫過類似下面這樣風格的代碼:

          復制代碼
          <script type="text/javascript">     var a = 1;     var b = 2;     var c = a * a + b * b;      if(c> 1) {         alert('c > 1');     }      function add(a, b) {         return a + b;     }      c = add(a,b); </script>
          復制代碼
          <a href="javascript:;" onclick="click(this);" title="">請點擊</a>

          這些代碼的特點是:

          • 到處可見的全局變量
          • 大量的函數
          • 內嵌在html元素上的各種js調用

          當然這些代碼本身在實現功能上并沒有錯誤,但是從代碼的可重用性,健壯性以及可維護性來說,這種編程方式是有問題的,尤其是在頁面邏輯較為復雜的應用中,這些問題會暴露地特別明顯:

          • 全局變量極易造成命名沖突
          • 函數式編程非常不利于代碼的組織和管理
          • 內嵌的js調用很不利于代碼的維護,因為html代碼有的時候是十分臃腫和龐大的

          所以當這些問題出現的時候,js大牛們就開始尋找去解決這些問題的究極辦法,于是模塊化開發就出現了。正如模塊化這個概念的表面意思一樣,它要求在 編寫代碼的時候,按層次,按功能,將獨立的邏輯,封裝成可重用的模塊,對外提供直接明了的調用接口,內部實現細節完全私有,并且模塊之間的內部實現在執行 期間互不干擾,最終的結果就是可以解決前面舉例提到的問題。一個簡單遵循模塊化開發要求編寫的例子:

          復制代碼
          //module.js var student = function (name) {         return name && {                 getName: function () {                     return name;                 }             };     },     course = function (name) {         return name && {                 getName: function () {                     return name;                 }             }     },     controller = function () {         var data = {};         return {             add: function (stu, cour) {                 var stuName = stu && stu.getName(),                     courName = cour && cour.getName(),                     current,                     _filter = function (e) {                         return e === courName;                     };                  if (!stuName || !courName) return;                  current = data[stuName] = data[stuName] || [];                  if (current.filter(_filter).length === 0) {                     current.push(courName);                 }             },             list: function (stu) {                 var stuName = stu && stu.getName(),                     current = data[stuName];                 current && console.log(current.join(';'));             }         }     };  //main.js  var stu = new student('lyzg'),     c = new controller();  c.add(stu,new course('javascript')); c.add(stu,new course('html')); c.add(stu,new course('css')); c.list(stu);
          復制代碼

          以上代碼定義了三個模塊分別表示學生,課程和控制器,然后在main.js中調用了controller提供的add和list接口,為lyzg這個學生添加了三門課程,然后在控制臺顯示了出來。運行結果如下:

          javascript;html;css

          通過上例,可以看出模塊化的代碼結構和邏輯十分清晰,代碼看起來十分優雅,另外由于邏輯都通過模塊拆分,所以達到了解耦的目的,代碼的功能也會比較 健壯。不過上例使用的這種模塊化開發方式也并不是沒有問題,這個問題就是它還是把模塊引用如student這些直接添加到了全局空間下,雖然通過模塊減少 了很多全局空間的變量和函數,但是模塊引用本身還是要依賴全局空間,才能被調用,當模塊較多,或者有引入第三方模塊庫時,仍然可能造成命名沖突的問題,所 以這種全局空間下的模塊化開發的方式并不是最完美的方式。目前常見的模塊化開發方式,全局空間方式是最基本的一種,另外常見的還有遵循AMD規范的開發方 式,遵循CMD規范的開發方式,和ECMAScript 6的開發方式。需要說明的是,CMD和ES6跟本文的核心沒有關系,所以不會在此介紹,后面的內容主要介紹AMD以及實現了AMD規范的 RequireJS。

          2. AMD規范

          正如上文提到,實現模塊化開發的方式,另外常見的一種就是遵循AMD規范的實現方式,不過AMD規范并不是具體的實現方式,而僅僅是模塊化開發的一 種解決方案,你可以把它理解成模塊化開發的一些接口聲明,如果你要實現一個遵循該規范的模塊化開發工具,就必須實現它預先定義的API。比如它要求在加載 模塊時,必須使用如下的API調用方式:

          require([module], callback) 其中: [module]:是一個數組,里面的成員就是要加載的模塊; callback:是模塊加載完成之后的回調函數

          所有遵循AMD規范的模塊化工具,都必須按照它的要求去實現,比如RequireJS這個庫,就是完全遵循AMD規范實現的,所以在利用 RequireJS加載或者調用模塊時,如果你事先知道AMD規范的話,你就知道該怎么用RequireJS了。規范的好處在于,不同的實現卻有相同的調 用方式,很容易切換不同的工具使用,至于具體用哪一個實現,這就跟各個工具的各自的優點跟項目的特點有關系,這些都是在項目開始選型的時候需要確定的。目 前RequireJS不是唯一實現了AMD規范的庫,像Dojo這種更全面的js庫也都有AMD的實現。

          最后對AMD全稱做一個解釋,譯為:異步模塊定義。異步強調的是,在加載模塊以及模塊所依賴的其它模塊時,都采用異步加載的方式,避免模塊加載阻塞了網頁的渲染進度。相比傳統的異步加載,AMD工具的異步加載更加簡便,而且還能實現按需加載,具體解釋在下一部分說明。

          3. JavaScript的異步加載和按需加載

          html中的script標簽在加載和執行過程中會阻塞網頁的渲染,所以一般要求盡量將script標簽放置在body元素的底部,以便加快頁面顯示的速度,還有一種方式就是通過異步加載的方式來加載js,這樣可以避免js文件對html渲染的阻塞。

          第1種異步加載的方式是直接利用腳本生成script標簽的方式:

          復制代碼
          (function() {     var s = document.createElement('script');     s.type = 'text/javascript';     s.async = true;     s.src = 'http://yourdomain.com/script.js';     var x = document.getElementsByTagName('script')[0];     x.parentNode.insertBefore(s, x); })();
          復制代碼

          這段代碼,放置在script標記內部,然后該script標記添加到body元素的底部即可。

          第2種方式是借助script的屬性:defer和async,defer這個屬性在IE瀏覽器和早起的火狐瀏覽器中支持,async在支持 html5的瀏覽器上都支持,只要有這兩個屬性,script就會以異步的方式來加載,所以script在html中的位置就不重要了:

          <script defer async="true" type="text/javascript" src="app/foo.js"></script> <script defer async="true" type="text/javascript" src="app/bar.js"></script>
          <script defer async="true" type="text/javascript" src="app/main.js"></script>

          這種方式下,所有異步js在執行的時候還是按順序執行的,不然就會存在依賴問題,比如如果上例中的main.js依賴foo.js和bar.js, 但是main.js先執行的話就會出錯了。雖然從來理論上這種方式也算不錯了,但是不夠好,因為它用起來很繁瑣,而且還有個問題就是頁面需要添加多個 script標記以及沒有辦法完全做到按需加載。

          JS的按需加載分兩個層次,第一個層次是只加載這個頁面可能被用到的JS,第二個層次是在只在用到某個JS的時 候才去加載。傳統地方式很容易做到第一個層次,但是不容易做到第二個層次,雖然我們可以通過合并和壓縮工具,將某個頁面所有的JS都添加到一個文件中去, 最大程度減少資源請求量,但是這個JS請求到客戶端以后,其中有很多內容可能都用不上,要是有個工具能夠做到在需要的時候才去加載相關js就完美解決問題 了,比如RequireJS。

          4. RequireJS常用用法總結

          前文多次提及RequireJS,本部分將對它的常用用法詳細說明,它的官方地址是:http://www.requirejs.cn/,你可以到該地址去下載最新版RequireJS文件。RequireJS作為目前使用最廣泛的AMD工具,它的主要優點是:

          • 完全支持模塊化開發
          • 能將非AMD規范的模塊引入到RequireJS中使用
          • 異步加載JS
          • 完全按需加載依賴模塊,模塊文件只需要壓縮混淆,不需要合并
          • 錯誤調試
          • 插件支持

          4.01 如何使用RequireJS

          使用方式很簡單,只要一個script標記就可以在網頁中加載RequireJS:

          <script defer async="true" src="/bower_components/requirejs/require.js"></script>

          由于這里用到了defer和async這兩個異步加載的屬性,所以require.js是異步加載的,你把這個script標記放置在任何地方都沒有問題。

          4.02 如何利用RequireJS加載并執行當前網頁的邏輯JS

          4.01解決的僅僅是RequireJS的使用問題,但它僅僅是一個JS庫,是一個被當前頁面的邏輯所利用的工具,真正實現網頁功能邏輯的是我們要 利用RequireJS編寫的主JS,這個主JS(假設這些代碼都放置在main.js文件中)又該如何利用RJ來加載執行呢?方式如下:

          <script data-main="scripts/main.js" defer async="true" src="/bower_components/requirejs/require.js"></script>

          對比4.01,你會發現script標記多了一個data-main,RJ用這個配置當前頁面的主JS,你要把邏輯都寫在這個main.js里面。 當RJ自身加載執行后,就會再次異步加載main.js。這個main.js是當前網頁所有邏輯的入口,理想情況下,整個網頁只需要這一個script標 記,利用RJ加載依賴的其它文件,如jquery等。

           

          4.03 main.js怎么寫

          假設項目的目錄結構為:

          clipboard_thumb

          main.js是跟當前頁面相關的主JS,app文件夾存放本項目自定義的模塊,lib存放第三方庫。

          html中按4.02的方式配置RJ。main.js的代碼如下:

          require(['lib/foo', 'app/bar', 'app/app'], function(foo, bar, app) {     //use foo bar app do sth });

          在這段JS中,我們利用RJ提供的require方法,加載了三個模塊,然后在這個三個模塊都加載成功之后執行頁面邏輯。require方法有2個 參數,第一個參數是數組類型的,實際使用時,數組的每個元素都是一個模塊的module ID,第二個參數是一個回調函數,這個函數在第一個參數定義的所有模塊都加載成功后回調,形參的個數和順序分別與第一個參數定義的模塊對應,比如第一個模 塊時lib/foo,那么這個回調函數的第一個參數就是foo這個模塊的引用,在回調函數中我們使用這些形參來調用各個模塊的方法,由于回調是在各模塊加 載之后才調用的,所以這些模塊引用肯定都是有效的。

          從以上這個簡短的代碼,你應該已經知道該如何使用RJ了。

          4.04 RJ的baseUrl和module ID

          在介紹RJ如何去解析依賴的那些模塊JS的路徑時,必須先弄清楚baseUrl和module ID這兩個概念。

          html中的base元素可以定義當前頁面內部任何http請求的url前綴部分,RJ的baseUrl跟這個base元素起的作用是類似的,由于 RJ總是動態地請求依賴的JS文件,所以必然涉及到一個JS文件的路徑解析問題,RJ默認采用一種baseUrl + moduleID的解析方式,這個解析方式后續會舉例說明。這個baseUrl非常重要,RJ對它的處理遵循如下規則:

          • 在沒有使用data-main和config的情況下,baseUrl默認為當前頁面的目錄
          • 在有data-main的情況下,main.js前面的部分就是baseUrl,比如上面的scripts/
          • 在有config的情況下,baseUrl以config配置的為準

          上述三種方式,優先級由低到高排列。

          data-main的使用方式,你已經知道了,config該如何配置,如下所示:

          require.config({     baseUrl: 'scripts' });

          這個配置必須放置在main.js的最前面。data-main與config配置同時存在的時候,以config為準,由于RJ的其它配置也是在這個位置配置的,所以4.03中的main.js可以改成如下結構,以便將來的擴展:

          復制代碼
          require.config({     baseUrl: 'scripts' });  require(['lib/foo', 'app/bar', 'app/app'], function(foo, bar, app) {     // use foo bar app do sth });
          復制代碼

           

          關于module ID,就是在require方法以及后續的define方法里,用在依賴數組這個參數里,用來標識一個模塊的字符串。上面代碼中的['lib/foo', 'app/bar', 'app/app']就是一個依賴數組,其中的每個元素都是一個module ID。值得注意的是,module ID并不一定是該module 相關JS路徑的一部分,有的module ID很短,但可能路徑很長,這跟RJ的解析規則有關。下一節詳細介紹。

          4.05 RJ的文件解析規則

          RJ默認按baseUrl + module ID的規則,解析文件,并且它默認要加載的文件都是js,所以你的module ID里面可以不包含.js的后綴,這就是為啥你看到的module ID都是lib/foo, app/bar這種形式了。有三種module ID,不適用這種規則:

          假如main.js如下使用:

          復制代碼
          require.config({     baseUrl: 'scripts' });  require(['/lib/foo', 'test.js', 'http://cdn.baidu.com/js/jquery'], function(foo, bar, app) {     // use foo bar app do sth });
          復制代碼

          這三個module 都不會根據baseUrl + module ID的規則來解析,而是直接用module ID來解析,等效于下面的代碼:

          <script src="/lib/foo.js"></script> <script src="test.js"></script> <script src="http://cdn.baidu.com/js/jquery.js"></script>

          各種module ID解析舉例:

          例1,項目結構如下:

          clipboard4_thumb

          main.js如下:

          復制代碼
          require.config({     baseUrl: 'scripts' });  require(['lib/foo', 'app/bar', 'app/app'], function(foo, bar, app) {     // use foo bar app do sth });
          復制代碼

          baseUrl為:scripts目錄

          moduleID為:lib/foo, app/bar, app/app

          根據baseUrl + moduleID,以及自動補后綴.js,最終這三個module的js文件路徑為:

          scripts/lib/foo.js scripts/app/bar.js scripts/app/app.js

          例2,項目結構同例1:

          main.js改為:

          復制代碼
          require.config({     baseUrl: 'scripts/lib',     paths: {      app: '../app'     } });   require(['foo', 'app/bar', 'app/app'], function(foo, bar, app) {     // use foo bar app do sth });
          復制代碼

          這里出現了一個新的配置paths,它的作用是針對module ID中特定的部分,進行轉義,如以上代碼中對app這個部分,轉義為../app,這表示一個相對路徑,相對位置是baseUrl所指定的目錄,由項目結 構可知,../app其實對應的是scirpt/app目錄。正因為有這個轉義的存在,所以以上代碼中的app/bar才能被正確解析,否則還按 baseUrl + moduleID的規則,app/bar不是應該被解析成scripts/lib/app/bar.js嗎,但實際并非如此,app/bar被解析成 scripts/app/bar.js,其中起關鍵作用的就是paths的配置。通過這個舉例,可以看出module ID并不一定是js文件路徑中的一部分,paths的配置對于路徑過程的js特別有效,因為可以簡化它的module ID。

          另外第一個模塊的ID為foo,同時沒有paths的轉義,所以根據解析規則,它的文件路徑時:scripts/lib/foo.js。

          paths的配置中只有當模塊位于baseUrl所指定的文件夾的同層目錄,或者更上層的目錄時,才會用到../這種相對路徑。

          例3,項目結果同例1,main.js同例2:

          這里要說明的問題稍微特殊,不以main.js為例,而以app.js為例,且app依賴bar,當然config還是需要在main.js中定義的,由于這個問題在定義模塊的時候更加常見,所以用define來舉例,假設app.js模塊如下定義:

          復制代碼
          define(['./bar'], function(bar) {      return {           doSth: function() {               bar.doSth();           }      } });
          復制代碼

          上面的代碼通過define定義了一個模塊,這個define函數后面介紹如何定義模塊的時候再來介紹,這里簡單了解。這里這種用法的第一個參數跟 require函數一樣,是一個依賴數組,第二個參數是一個回調,也是在所有依賴加載成功之后調用,這個回調的返回值會成為這個模塊的引用被其它模塊所使 用。

          這里要說的問題還是跟解析規則相關的,如果完全遵守RJ的解析規則,這里的依賴應該配置成app/bar才是正確的,但由于app.js與 bar.js位于同一個目錄,所以完全可利用./這個同目錄的相對標識符來解析js,這樣的話只要app.js已經加載成功了,那么去同目錄下找 bar.js就肯定能找到了。這種配置在定義模塊的時候非常有意義,這樣你的模塊就不依賴于放置這些模塊的文件夾名稱了。

          4.06 RJ的異步加載

          RJ不管是require方法還是define方法的依賴模塊都是異步加載的,所以下面的代碼不一定能解析到正確的JS文件:

          <script data-main="scripts/main" src="scripts/require.js"></script> <script src="scripts/other.js"></script>
          //main.js
          require.config({ paths: { foo:
          'libs/foo-1.1.3' } });
          //other.js
          require( ['foo'], function( foo ) { //foo is undefined });

          由于main.js是異步加載的,所以other.js會比它先加載,但是RJ的配置存在于main.js里面,所以在加載other.js讀不到RJ的配置,在other.js執行的時候解析出來的foo的路徑就會變成scripts/foo.js,而正確路徑應該是scripts/libs/foo-1.1.3.js。

          盡管RJ的依賴是異步加載的,但是已加載的模塊在多次依賴的時候,不會再重新加載:

          define(['require', 'app/bar', 'app/app'], function(require) {     var bar= require("app/bar");     var app= require("app/app");     //use bar and app do sth });

          上面的代碼,在callback定義的時候,只用了一個形參,這主要是為了減少形參的數量,避免整個回調的簽名很長。依賴的模塊在回調內部可以直接用require(moduleID)的參數得到,由于在回調執行前,依賴的模塊已經加載,所以此處調用不會再重新加載。但是如果此處獲取一個并不在依賴數組中出現的module ID,require很有可能獲取不到該模塊引用,因為它可能需要重新加載,如果它沒有在其它模塊中被加載過的話。

          4.07 RJ官方推薦的JS文件組織結構

          RJ建議,文件組織盡量扁平,不要多層嵌套,最理想的是跟項目相關的放在一個文件夾,第三方庫放在一個文件夾,如下所示:

          image_thumb

          4.08 使用define定義模塊

          AMD規定的模塊定義規范為:

          define(id?, dependencies?, factory);  其中: id: 模塊標識,可以省略。 dependencies: 所依賴的模塊,可以省略。 factory: 模塊的實現,或者一個JavaScript對象

          關于第一個參數,本文不會涉及,因為RJ建議所有模塊都不要使用第一個參數,如果使用第一個參數定義的模塊成為命名模塊,不適用第一個參數的模塊成為匿名模塊,命名模塊如果更名,所有依賴它的模塊都得修改!第二個參數是依賴數組,跟require一樣,如果沒有這個參數,那么定義的就是一個無依賴的模塊;最后一個參數是回調或者是一個簡單對象,在模塊加載完畢后調用,當然沒有第二個參數,最后一個參數也會調用。

          本部分所舉例都采用如下項目結構:

          clipboard1_thumb

          1. 定義簡單對象模塊:

          app/bar.js

          define({  bar:'I am bar.' });

          利用main.js測試:

          復制代碼
          require.config({     baseUrl: 'scripts/lib',     paths: {         app: '../app'     } });  require(['app/bar'], function(bar) {     console.log(bar);// {bar: 'I am bar.'} });
          復制代碼

          2. 定義無依賴的模塊:

          app/nodec.js:

          define(function () {     return {         nodec: "yes, I don't need dependence."     } });

          利用main.js測試:

          復制代碼
          require.config({     baseUrl: 'scripts/lib',     paths: {         app: '../app'     } });  require(['app/nodec'], function(nodec) {     console.log(nodec);// {nodec: yes, I don't need dependence.'} });
          復制代碼

          3. 定義依賴其它模塊的模塊:

          app/dec.js:

          define(['jquery'], function($){     //use $ do sth ...     return {        useJq: true     } });

          利用main.js測試:

          復制代碼
          require.config({     baseUrl: 'scripts/lib',     paths: {         app: '../app'     } });  require(['app/dec'], function(dec) {     console.log(dec);//{useJq: true} });
          復制代碼

          4. 循環依賴:

          當一個模塊foo的依賴數組中存在bar,bar模塊的依賴數組中存在foo,就會形成循環依賴,稍微修改下bar.js和foo.js如下。

          app/bar.js:

          復制代碼
          define(['foo'],function(foo){  return {   name: 'bar',   hi: function(){    console.log('Hi! ' + foo.name);   }  } });
          復制代碼

          lib/foo.js:

          復制代碼
          define(['app/bar'],function(bar){  return {   name: 'foo',   hi: function(){    console.log('Hi! ' + bar.name);   }  } });
          復制代碼

          利用main.js測試:

          復制代碼
          require.config({     baseUrl: 'scripts/lib',     paths: {         app: '../app'     } });   require(['app/bar', 'foo'], function(bar, foo) {     bar.hi();     foo.hi(); });
          復制代碼

          運行結果:

          clipboard3_thumb1

          如果改變main.js中require部分的依賴順序,結果:

          clipboard5_thumb1

          循環依賴導致兩個依賴的module之間,始終會有一個在獲取另一個的時候,得到undefined。解決方法是,在定義module的時候,如果用到循環依賴的時候,在define內部通過require重新獲取。main.js不變,bar.js改成:

          復制代碼
          define(['require', 'foo'], function(require, foo) {     return {         name: 'bar',         hi: function() {          foo = require('foo');             console.log('Hi! ' + foo.name);         }     } });
          復制代碼

          foo.js改成:

          復制代碼
          define(['require', 'app/bar'], function(require, bar) {     return {         name: 'foo',         hi: function() {          bar = require('app/bar');             console.log('Hi! ' + bar.name);         }     } });
          復制代碼

          利用上述代碼,重新執行,結果是:

          clipboard7_thumb

          模塊定義總結:不管模塊是用回調函數定義還是簡單對象定義,這個模塊輸出的是一個引用,所以這個引用必須是有效的,你的回調不能返回undefined,但是不局限于對象類型,還可以是數組,函數,甚至是基本類型,只不過如果返回對象,你能通過這個對象組織更多的接口。

          4.09 內置的RJ模塊

          再看看這個代碼:

          復制代碼
          define(['require', 'app/bar'], function(require) {     return {         name: 'foo',         hi: function() {             var bar = require('app/bar');             console.log('Hi! ' + bar.name);         }     } });
          復制代碼

          依賴數組中的require這個moduleID對應的是一個內置模塊,利用它加載模塊,怎么用你已經看到了,比如在main.js中,在define中。另外一個內置模塊是module,這個模塊跟RJ的另外一個配置有關,具體用法請在第5大部分去了解。

          4.10 其它RJ有用功能

          1. 生成相對于模塊的URL地址

          define(["require"], function(require) {     var cssUrl = require.toUrl("./style.css"); });

          這個功能在你想要動態地加載一些文件的時候有用,注意要使用相對路徑。

          2. 控制臺調試

          require("module/name").callSomeFunction()

          假如你想在控制臺中查看某個模塊都有哪些方法可以調用,如果這個模塊已經在頁面加載的時候通過依賴被加載過后,那么就可以用以上代碼在控制臺中做各種測試了。

          5. RequireJS常用配置總結

          在RJ的配置中,前面已經接觸到了baseUrl,paths,另外幾個常用的配置是:

          • shim
          • config
          • enforceDefine
          • urlArgs

          5.01 shim

          為那些沒有使用define()來聲明依賴關系、設置模塊的"瀏覽器全局變量注入"型腳本做依賴和導出配置。

          例1:利用exports將模塊的全局變量引用與RequireJS關聯

          項目結構如圖:

          clipboard3_thumb

          main.js如下:

          復制代碼
          require.config({     baseUrl: 'scripts/lib',     paths: {         app: '../app'     },     shim: {      underscore: {       exports: '_'      }     } });  require(['underscore'], function(_) {     // 現在可以通過_調用underscore的api了 });
          復制代碼

          如你所見,RJ在shim中添加了一個對underscore這個模塊的配置,并通過exports屬性指定該模塊暴露的全局變量,以便RJ能夠對這些模塊統一管理。

          例2:利用deps配置js模塊的依賴

          項目結構如圖:

          clipboard5_thumb

          main.js如下:

          復制代碼
          require.config({     baseUrl: 'scripts/lib',     paths: {         app: '../app'     },     shim: {      backbone: {         deps: ['underscore', 'jquery'],         exports: 'Backbone'      }     } });  require(['backbone'], function(Backbone) {     //use Backbone's API });
          復制代碼

          由于backbone這個組件依賴jquery和underscore,所以可以通過deps屬性配置它的依賴,這樣backbone將會在另外兩個模塊加載完畢之后才會加載。

          例3:jquery等庫插件配置方法

          代碼舉例如下:

          復制代碼
          requirejs.config({     shim: {         'jquery.colorize': {             deps: ['jquery'],             exports: 'jQuery.fn.colorize'         },         'jquery.scroll': {             deps: ['jquery'],             exports: 'jQuery.fn.scroll'         },         'backbone.layoutmanager': {             deps: ['backbone']             exports: 'Backbone.LayoutManager'         }     } });
          復制代碼

           

          5.02 config

          常常需要將配置信息傳給一個模塊。這些配置往往是application級別的信息,需要一個手段將它們向下傳遞給模塊。在RequireJS中,基于requirejs.config()的config配置項來實現。要獲取這些信息的模塊可以加載特殊的依賴“module”,并調用module.config()。

          例1:在requirejs.config()中定義config,以供其它模塊使用

          復制代碼
          requirejs.config({     config: {         'bar': {             size: 'large'         },         'baz': {             color: 'blue'         }     } });
          復制代碼

          如你所見,config屬性中的bar這一節是在用于module ID為bar這個模塊的,baz這一節是用于module ID為baz這個模塊的。具體使用以bar.js舉例:

          define(['module'], function(module) {     //Will be the value 'large'var size = module.config().size; });

          前面提到過,RJ的內置模塊除了require還有一個module,用法就在此處,通過它可以來加載config的內容。

          5.03 enforceDefine

          如果設置為true,則當一個腳本不是通過define()定義且不具備可供檢查的shim導出字串值時,就會拋出錯誤。這個屬性可以強制要求所有RJ依賴或加載的模塊都要通過define或者shim被RJ來管理,同時它還有一個好處就是用于錯誤檢測。

          5.04 urlArgs

          RequireJS獲取資源時附加在URL后面的額外的query參數。作為瀏覽器或服務器未正確配置時的“cache bust”手段很有用。使用cache bust配置的一個示例:

          urlArgs: "bust=" + (new Date()).getTime()

          6. 錯誤處理

          6.01 加載錯誤的捕獲

          IE中捕獲加載錯誤不完美:

          • IE 6-8中的script.onerror無效。沒有辦法判斷是否加載一個腳本會導致404錯;更甚地,在404中依然會觸發state為complete的onreadystatechange事件。
          • IE 9+中script.onerror有效,但有一個bug:在執行腳本之后它并不觸發script.onload事件句柄。因此它無法支持匿名AMD模塊的標準方法。所以script.onreadystatechange事件仍被使用。但是,state為complete的onreadystatechange事件會在script.onerror函數觸發之前觸發。

          所以為了支持在IE中捕獲加載錯誤,需要配置enforceDefine為true,這不得不要求你所有的模塊都用define定義,或者用shim配置RJ對它的引用。

          注意:如果你設置了enforceDefine: true,而且你使用data-main=""來加載你的主JS模塊,則該主JS模塊必須調用define()而不是require()來加載其所需的代碼。主JS模塊仍然可調用require/requirejs來設置config值,但對于模塊加載必須使用define()。比如原來的這段就會報錯:

          復制代碼
          require.config({  enforceDefine: true,     baseUrl: 'scripts/lib',     paths: {         app: '../app'     },     shim: {      backbone: {       deps: ['underscore', 'jquery'],             exports: 'Backbone'      }     } }); require(['backbone'], function(Backbone) {     console.log(Backbone); });
          復制代碼

          把最后三行改成:

          define(['backbone'], function(Backbone) {     console.log(Backbone); });

          才不會報錯。

          6.02 paths備錯

          復制代碼
          requirejs.config({     //To get timely, correct error triggers in IE, force a define/shim exports check.     enforceDefine: true,     paths: {         jquery: [             'http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min',             //If the CDN location fails, load from this location             'lib/jquery'         ]     } });  //Later require(['jquery'], function ($) { });
          復制代碼

          上述代碼先嘗試加載CDN版本,如果出錯,則退回到本地的lib/jquery.js。

          注意: paths備錯僅在模塊ID精確匹配時工作。這不同于常規的paths配置,常規配置可匹配模塊ID的任意前綴部分。備錯主要用于非常的錯誤恢復,而不是常規的path查找解析,因為那在瀏覽器中是低效的。

          6.03 全局 requirejs.onError

          為了捕獲在局域的errback中未捕獲的異常,你可以重載requirejs.onError():

          復制代碼
          requirejs.onError = function (err) {     console.log(err.requireType);     if (err.requireType === 'timeout') {         console.log('modules: ' + err.requireModules);     }      throw err; };
          復制代碼

          (完)

          posted on 2016-03-04 15:27 SIMONE 閱讀(873) 評論(0)  編輯  收藏 所屬分類: JavaScript
          主站蜘蛛池模板: 德兴市| 达孜县| 锡林浩特市| 岳西县| 濮阳县| 天长市| 乐平市| 寿宁县| 朝阳区| 昭觉县| 河北区| 泸定县| 琼结县| 若羌县| 闸北区| 南召县| 百色市| 留坝县| 维西| 双江| 石嘴山市| 高雄市| 南溪县| 博罗县| 万载县| 涞水县| 布拖县| 莱州市| 左云县| 柯坪县| 惠州市| 台中县| 禹城市| 崇明县| 宣汉县| 和田县| 余姚市| 遵义市| 循化| 龙游县| 长宁县|