前言
進入移動前端是很不錯的選擇,這塊也是我希望的道路,但是不熟悉啊。。。
現在項目用的是require+backbone,整個框架被封裝了一次,今天看了代碼搞不清楚,覺得應該先從源頭抓起,所以再看看require了。
上午是到處搜集的資料,下午我們來看原生的API吧:
http://www.requirejs.org/docs/api.html#config
PS:我英語很爛,各位將就着看吧,看到紅色就說明老夫拿不准......
加載javascript文件
RequireJS采用不同的方法來加載腳本,他鼓勵模塊化編程,使用RequireJS編程不但可以模塊化編程而且他依舊可以運行的很快。
RequireJS鼓勵使用模塊ID,而不是像原來那樣使用script標簽使用url引入。
RequireJS加載代碼時候,其相對路徑為baseUrl,baseUrl通常被設置為data-main指定文件的目錄:
<!--這里講baseUrl設置為script的話,scripts/main.js便可以寫成main了--> <script data-main="scripts/main.js" src="scripts/require.js"></script>
BaseUrl也可以通過設置進行手動配置(通過RequireJS 的 config進行配置),若是沒在config中進行配置,並且script標簽沒有指定data-main的話,那么默認目錄為引入requireJS的HTML頁面目錄。
默認情況下不要在模塊id上加上.js后綴,requireJS會在運行時自己加上。
通過設置config中的paths(對象字面量)屬性,你能設置一組腳本的位置,如此便能減少我們的js總體配置。
這里我們來舉個例子,且看我們的文檔目錄:

我們index代碼:
<script data-main="js/app.js" src="js/require.js"></script>
app.js為入口函數,其代碼為:
requirejs.config({ //默認情況下模塊所在目錄為js/lib baseUrl: 'js/lib', //當模塊id前綴為app時,他便由js/app加載模塊文件
//這里設置的路徑是相對與baseUrl的,不要包含.js paths: { app: '../app' } }); // 開始邏輯. requirejs(['jquery', 'canvas', 'app/sub'], function ($, canvas, sub) { //jQuery, canvas and the app/sub module are all //loaded and can be used here now. });
各位請注意,這里的jquery並沒有在他們的文件名上加上其版本號,這里推薦加上。
PS:原因我就不說了,說也不一定說得清楚......
理想情況下我們加載的腳步都會通過define()函數定義,但是我們有些腳步會依賴與當前版本不同的版本,你能使用shim配置,來表達其依賴。
PS:這里有點模糊,我們再來看看snandy道友是怎么說的:
shim參數解決了使用非AMD方式定義的模塊(如jQuery插件)及其載入順序。
使用shim參數來取代1.0版本的order插件。其實在1.0版本中就曾經有人開發過use和wrap插件來解決此類問題。
考慮到很多開發者有此類需求(比如某些JS模塊是較早時候其他人開發的,非AMD方式)此次2.0版本直接將其內置其中。
這里是一個使用jQuery插件形式配置的參數,我們知道jQuery插件本質是將命名空間掛在全局jQuery或jQuery.fn上,而非使用define定義的模塊。
jQuery插件皆依賴於jQuery,即在require插件時得保證jQuery先下載:
1 require.config({ 2 shim: { 3 'jquery-slide': ['jquery'] 4 } 5 }); 6 require(['jquery-slide']);
這里便會保證先加載jquery再加載插件。
PS:對照着園友的解釋看看吧,應該會清晰一點,這塊后面還會有我們等下再看。
模塊定義
requireJS定義模塊與傳統一個很大的不同是他可以保證其定義的變量處於某個范圍內,從而避免了全局命名污染。
他能明確的羅列出其依賴,並且在那些依賴上找到處理辦法,而不是必須對那些依賴指定全局變量。
requireJS的模塊擴展不需要全局變量與其他模塊產生依賴(理解的狗屁不通啊)
PS:文字讀不懂,來一個簡單的鍵值對例子吧:
define({ color: "black", size: "unisize" });
若是這個模塊沒有任何依賴,並且他僅僅是一組鍵值對,那么就傳遞一個對象就好。
定義函數
//my/shirt.js now does setup work //before returning its module definition. define(function () { //Do setup work here return { color: "black", size: "unisize" } });
若是模塊沒有依賴,但是需要用一個函數做一些初始化工作,然后定義自己通過define的匿名函數。
有依賴的模塊
//my/shirt.js now has some dependencies, a cart and inventory //module in the same directory as shirt.js define(["./cart", "./inventory"], function(cart, inventory) { //return an object to define the "my/shirt" module. return { color: "blue", size: "large", addToCart: function() { inventory.decrement(this); cart.add(this); } } } );
若是模塊具有依賴關系,第一個參數應該是一個數組,其項目為依賴名字,第二個參數是匿名函數
匿名函數在依賴項加載結束后會立即加載,函數會返回一個對象用以定義這個模塊。
前面的依賴項將以參數的形式傳遞給函數,順序與之前一致。
再看我們的例子,一個球衣模塊被創建了(我們返回的是一個衣服模塊)
PS:這里文件命名為shirt.js,所以返回的就是衣服模塊了
最后我們得到的結構式這樣的:
- my/cart.js
- my/inventory.js
- my/shirt.js
參數調用時的參數與前面依賴項一一對應,
定義函數模塊
//A module definition inside foo/title.js. It uses //my/cart and my/inventory modules from before, //but since foo/bar.js is in a different directory than //the "my" modules, it uses the "my" in the module dependency //name to find them. The "my" part of the name can be mapped //to any directory, but by default, it is assumed to be a //sibling to the "foo" directory. define(["my/cart", "my/inventory"], function(cart, inventory) { //return a function to define "foo/title". //It gets or sets the window title. return function(title) { return title ? (window.title = title) : inventory.storeName + ' ' + cart.name; } } );
模塊也可以不必返回對象,任何有效的返回都是可以的,比如上面的例子,返回一個函數作為其模塊定義。
帶名字的模塊
//Explicitly defines the "foo/title" module: define("foo/title", ["my/cart", "my/inventory"], function(cart, inventory) { //Define foo/title object in here. } );
(???)這里明確的定義了foo/title模塊,這里其實是一種優化手段,我們這里可以明確的命名模塊,但是若是文件目錄變化我們就要更改名稱了。
其他說明
一個js文件應該只定義一個模塊,並與文件目錄一致,因為最后有個神馬優化工具可以優化。。。
在定義模塊時將各個模塊關聯起來,
相對模塊生產url,你可能需要使用一個相對模塊的url:
define(["require"], function(require) { var cssUrl = require.toUrl("./style.css"); });
PS:尼瑪,我今天才知道我英語有多差。。。
循環依賴
我們有時候會定於循環依賴的模塊,比如a需要b並且b需要a,在這個情況下當b模塊調用時他將會從a獲得一個undefined值,b可以通過require方法取得一個比較晚的模塊。
//Inside b.js: define(["require", "a"], function(require, a) { //"a" in this case will be null if a also asked for b, //a circular dependency. return function(title) { return require("a").doSomething(); } } );
你通常不需要使用require方法獲取一個模塊,在循環依賴時候需要用到(讀不懂了。。。)
exports
//Inside b.js: define(function(require, exports, module) { //If "a" has used exports, then we have a real //object reference here. However, we cannot use //any of a's properties until after b returns a value. var a = require("a"); exports.foo = function () { return a.bar(); }; });
//Inside b.js: define(['a', 'exports'], function(a, exports) { //If "a" has used exports, then we have a real //object reference here. However, we cannot use //any of a's properties until after b returns a value. exports.foo = function () { return a.bar(); }; });
配置選項
我們可以通過以下方法,對require進行配置:
<script src="scripts/require.js"></script> <script> require.config({ baseUrl: "/another/path", paths: { "some": "some/v1.0" }, waitSeconds: 15 }); require( ["some/module", "my/module", "a.js", "b.js"], function(someModule, myModule) { //This function will be called when all the dependencies //listed above are loaded. Note that this function could //be called before the page is loaded. //This callback is optional. } ); </script>
baseUrl
模塊查找的根目錄,默認情況與data-main所賦值處於同一目錄
paths
該項用於配置那些不在baseUrl下的模塊,這個指定的path假定是baseUrl的相對路徑,若是以/開頭的話就不是了。
這里的id會自動加上.js,我們要獲取一個路徑時,一般這個樣子干:
require.toUrl()
shim
傳統瀏覽器的全局腳本不使用define去聲明依賴關系和模塊設置值的依賴。
Ps:讀不懂,還是看代碼算了:
requirejs.config({ shim: { 'backbone': { deps: ['underscore', 'jquery'], exports: 'Backbone' }, 'underscore': { exports: '_' }, 'foo': { deps: ['bar'], exports: 'Foo', init: function (bar) { return this.Foo.noConflict(); } } } }); define(['backbone'], function (Backbone) { return Backbone.Model.extend({}); });
這個例子假定backbone等依賴庫已經在baseUrl中,若是沒有就需要配置。
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' } } });
結語
讀不下去啦,暫時這樣吧。。。。。。
