1. 程式人生 > >什麽是模塊化?

什麽是模塊化?

spa func 頁面 位置 技術 必須 們的 而且 先後

什麽是模塊化? 以前我們可能會這樣做代碼分工 modules.js ----- var moduleA = {......} var moduleB = {......} var moduleC = {......} 然後每個頁面都引入JS <script src="modules.js"></script> 不管這個頁面用到了幾個模塊,你都要把整個文件加載進來,於是我們就想,不如分開吧 然後我們的代碼變成了這樣: moduleA.js ----- var moduleA = {......} moduleB.js ----- var moduleB = {......} moduleC.js ----- var moduleC = {......} 但是,由於各個模塊之間存在相互引用的依賴關系,所以我們這樣引入JS: <script src="jquery.js"></script> <script src="moduleB.js"></script> <script src="moduleC.js"></script> <script src="moduleA.js"></script> 假設A引用了C,而C引用了B,ABC裏面都用到了JQ,你必須小心翼翼的確保它們的加載順序是正確的 於是require.js出現了 按照requireJS當中的規範要求,你只需加載一個文件就可以,但同時需要帶上一個配置文件config.js 第一步: <script data-main ="config.js" src ="require.js" ></script> 這個require.js你可以從官網下載,這個config.js你必須自己完成。不用擔心,它寫起來非常簡單: config.js ----- requirejs.config({ baseUrl : "js", paths : { "jquery": "jquery/jquery.1.11.3" } }); baseUrl的意思就是說你所有的路徑都是基於它基礎上的。 看的出來,我們正在配置一個文件的路徑 "jquery": "jquery/jquery.1.11.3" 左邊藍色的是我們定義的模塊名稱,右邊紅色則是文件路徑,註意文件沒有後綴名,因為在require看來所有的模塊都是JS 緊接著,我們可以定義自己的模塊文件了,moduleB.js 首先mouduleB.js也是一個模塊,但是我們必須對這個JS改造一下,讓它符合require的規範要求,才能使用 moduleB.js ----- define(["jquery"],function(jq){ //根據我們之前的設定,模塊B需要使用Jquery //define函數中的第一個參數,用來表明,我們即將引用哪個模塊。 //由於之前我們已經定義過了jquery模塊,所以這裏可以直接使用 //註意,你如果不寫聲明,這裏是用不了jQuery的 //你如果註意到第一個參數是一個數組,那就應該猜到,其實我們可以一次引用好多模塊 //jq變量就是jquery,你如果不習慣,把名字改回$就是了 return { start: function(){ jq("#box").show(1000); console.log("模塊B提供的start方法"); //為什麽這裏要return呢? 因為我們定義的模塊要被其他人使用 //那又為什麽要return對象呢?為了更符合模塊化思維以及面相對象的原則 //我們返回一個對象而不是函數,使用會更方便(待會講完怎麽調用你就知道了) } } }); 好了,模塊B定義完了,我們可以來試試。當然,用之前別忘了修改配置 config.js ----- requirejs.config({ baseUrl : "js", paths : { "jquery": "jquery/jquery.1.11.3", "moduleb" : "ms/moduleB" } }); 註意:配置路徑時,排名不分先後,順序可以任意。 我們有一個index.html頁面,包含一個index.js文件。 index.js ----- require(["config",function(){ //config默認從項目根目錄找,由於我們的config.js就是放在根目錄下的 //只有先引用config,才能引用配置好的所有模塊 require(["jquery","moduleb"],function($,mb){ //我們引用兩個模塊jquery、moduleb mb.start(); //mb就是我們剛才在模塊B中返回的對象 }) }) 根據我們一開始的設定(A引用了C,而C引用了B,ABC裏面都用到了JQ ) 和上面的講解,你能否自己完成moduleC.js和moduleA.js? moduleC.js ----- define(["moduleb","jquery"],function(mb,$){ return { ....... } }); moduleA.js ----- define(["modulec","jquery"],function(mc,$){ return { ....... } }); 別忘了配置: config.js ----- .............. paths: { "jquery": "jquery/jquery.1.11.3", "modulea" : "ms/moduleA", "moduleb" : "ms/moduleB", "modulec" : "ms/moduleC" } .............. 一些問題: 問:加載配置文件的路徑問題? 根據你目前的頁面的業務JS文件的位置來決定,也就是說,復雜加載config的JS在哪裏,路徑就從哪裏開始
例如index.js在根目錄,config也在根目錄: require(["config"],function(){...}); 例如index.js在js目錄中,config在根目錄 require(["../oncfig"], function(){...}); 例如index.js在根目錄中,config在js目錄
require(["js/config", function(){...}]; 問:是不是所有要加載的模塊,都必須寫define函數,為什麽jquery就沒寫,一樣可以加載? 誰說JQ沒寫呢?這是jquery的部分源代碼。 ...... if ( typeof define === "function" && define.amd ) { define( "jquery", [], function() { return jQuery; }); } ...... 所以,所有的JS都必須遵循require的規範,才能夠正確的加載 問:我自己寫了一大堆的工具函數,請問怎麽加載? 首先,工具函數也可以用對象來表示 common.js ----- define(function(){ return { getStyle : function(){ ........ }, randomColor : function(){ ......... } } }); 當然如果你比較任性,非要寫成這個樣子: common.js ----- function getStyle(){ ......... } function randomColor(){ ........ } 解決辦法也是有的: 請百度requireJS, shim配置 問:有一些插件,本身沒有導出任何對象或核心函數,只是對某個框架的擴展,例如 my.jquery.scroll.js 該怎麽用? 官方文檔給出的答案是使用shim配置 config.js ----- require.config({ baseUrl: "js", paths: { "jquery" : "jquery.1.11.3", "jquery.scroll" : "my.jquery.scroll" }, shim: { "jquery.scroll": { deps: ["jquery"], exports: "jQuery.fn.scroll" } } }); 這是第一種方式, deps表示它依賴了哪個模塊,exports表示它輸出哪個函數,函數名字要和插件代碼裏保持一致 使用方式: index.js ----- require(["config",function(){ require(["jquery","jquery.scroll"],function($){ $("#box").scroll(500); }) }) ===================================================== 第二種配置方式: config.js ----- require.config({ baseUrl: "js", paths: { "jquery" : "jquery.1.11.3", "jquery.scroll" : "my.jquery.scroll" }, shim: { "jquery.scroll": ["jquery"] } }); 使用方法同上 But! 官方文檔又說,這樣使用可能導致錯誤! 請參考原文: 技術分享 所以,終極解決方案是,把插件改成define調用......... 問:如果我用到了兩個框架,Jquery和Zepto,他們的核心函數都叫$ ,那該怎麽辦呢? require(["jquery","zepto"],function(jq,zepto){ // 改個名字就不沖突了 }) 說一說好處: 講了這麽多,requirejs所倡導的模塊化開發,好處在哪裏呢? 1 你有沒有發現,整個項目當中,再也沒有出現一個全局變量? 2 你有沒有發現,你再也沒有考慮過加載順序的問題? 3 你有沒有發現,即使兩個框架名字沖突了也沒關系? 4 而且你肯定沒有發現,所有的JS文件的加載過程,已經變成了異步。 5 最後,你還發現,用了requireJS,你的代碼想不寫成面相對象都難?? 關於AMD和CMD 總在網上看大家討論AMD和CMD,到底是什麽東西呢? AMD就是require所倡導的模塊化開發的方式 還有一個叫CommonJS的,不過還是和requireJS有些區別,主要針對NODE後端開發 另外還有一個大名鼎鼎的SeaJS,作者是淘寶的玉伯,於是誕生了CMD規範 根據作者自己的介紹,SeaJS各方面都比requireJS強大 這個就不做評價了 至於區別呢? AMD推崇的是依賴前置: define(["a","b","c"],function(a,b,c){ //我們把所有依賴提前寫好了 a.doSomething (); //這裏直接使用 b.doSometing(); }) CMD推崇的是依賴就近: define(function(require, exports, module) { var a = require(‘./a‘); a.doSomething(); ......... var b = require(‘./b‘) // 依賴可以就近書寫,用到的時候再加載 b.doSomething() }) 當然requireJS也支持CMD的寫法,不過作者本人是不推薦這麽寫的

什麽是模塊化?