RequireJS API
- 使用§§ 1-1.3
- 載入 JavaScript 檔案§ 1.1
- data-main 進入點§ 1.2
- 定義模組§ 1.3
- 簡單的名稱/值對§ 1.3.1
- 定義函式§ 1.3.2
- 具有相依性的定義函式§ 1.3.3
- 定義模組為函式§ 1.3.4
- 定義模組為簡化的 CommonJS 包裝器§ 1.3.5
- 定義一個有名稱的模組§ 1.3.6
- 其他模組註解§ 1.3.7
- 循環依賴§ 1.3.8
- 指定一個 JSONP 服務依賴§ 1.3.9
- 取消定義一個模組§ 1.3.10
- 機制§§ 2
- 設定選項§§ 3
- 進階用法§§ 4-4.6
- 從套件載入模組§ 4.1
- 多版本支援§ 4.2
- 在頁面載入後載入程式碼§ 4.3
- Web Worker 支援§ 4.4
- Rhino 支援§ 4.5
- Nashorn 支援§ 4.6
- 處理錯誤§ 4.7
- 載入器外掛程式§§ 5-5.4
- 指定一個文字檔依賴§ 5.1
- 頁面載入事件支援/DOM 準備就緒§ 5.2
- 定義一個 I18N 捆綁§ 5.3
用法 § 1
載入 JavaScript 檔案 § 1.1
RequireJS 採用與傳統 <script> 標籤不同的腳本載入方法。雖然它也可以快速執行並最佳化,但主要目標是鼓勵模組化程式碼。作為其中的一部分,它鼓勵使用 模組 ID 而不是腳本標籤的 URL。
RequireJS 會載入所有相對於 baseUrl 的程式碼。baseUrl 通常設定為與資料主屬性中用於載入頁面頂層腳本的腳本相同的目錄。 資料主屬性 是 require.js 會檢查以開始載入腳本的特殊屬性。此範例會產生一個 baseUrl 為 scripts
<!--This sets the baseUrl to the "scripts" directory, and
loads a script that will have a module ID of 'main'-->
<script data-main="scripts/main.js" src="scripts/require.js"></script>
或者,baseUrl 可以透過 RequireJS 設定檔 手動設定。如果沒有明確的設定檔且未使用資料主,則預設的 baseUrl 會是執行 RequireJS 的 HTML 頁面所在的目錄。
RequireJS 預設也會假設所有相依性都是腳本,因此不會預期在模組 ID 上看到尾碼「.js」。RequireJS 會在將模組 ID 轉換為路徑時自動加上它。透過 路徑設定檔,您可以設定一組腳本的位置。所有這些功能讓您可以使用比傳統 <script> 標籤更短的字串來表示腳本。
有時您可能想要直接參照腳本,而不遵循「baseUrl + 路徑」規則來尋找它。如果模組 ID 具有下列特徵之一,則 ID 就不會透過「baseUrl + 路徑」設定檔傳遞,而只會像相對於文件的常規 URL 一樣處理
- 以「.js」結尾。
- 以「/」開頭。
- 包含 URL 協定,例如「http:」或「https:」。
不過,一般來說,最好使用 baseUrl 和「路徑」設定檔來設定模組 ID 的路徑。這樣做可以讓您更靈活地重新命名路徑和設定路徑到不同的位置,以進行最佳化建置。
同樣地,為了避免大量設定檔,最好避免腳本的深層資料夾階層,而應將所有腳本保留在 baseUrl 中,或者如果您想要將您的程式庫/供應商提供的程式碼與您的應用程式程式碼分開,請使用類似這樣的目錄配置
- www/
- index.html
- js/
- app/
- sub.js
- lib/
- jquery.js
- canvas.js
- app.js
- require.js
- app/
在 index.html 中
<script data-main="js/app.js" src="js/require.js"></script>
以及在 app.js 中
requirejs.config({
//By default load any module IDs from js/lib
baseUrl: 'js/lib',
//except, if the module ID starts with "app",
//load it from the js/app directory. paths
//config is relative to the baseUrl, and
//never includes a ".js" extension since
//the paths config could be for a directory.
paths: {
app: '../app'
}
});
// Start the main app logic.
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)的檔案名稱中沒有版本號碼。如果您想要追蹤版本資訊,建議將該資訊儲存在一個獨立的文字檔案中,或者如果您使用 volo 等工具,它會將版本資訊蓋在 package.json 上,但會將檔案保留在磁碟上,檔案名稱為「jquery.js」。這樣您就能擁有最精簡的組態,而不必針對每個函式庫在「路徑」組態中新增一個項目。例如,將「jquery」組態為「jquery-1.7.2」。
理想情況下,您載入的指令碼會是透過呼叫 define() 所定義的模組。不過,您可能需要使用一些傳統/舊版的「瀏覽器全域」指令碼,這些指令碼並未透過 define() 表達其相依性。針對這些指令碼,您可以使用 shim 組態 來適當地表達其相依性。
如果您未表達相依性,您可能會收到載入錯誤,因為 RequireJS 會非同步且無序地載入指令碼以提升速度。
data-main 進入點 § 1.2
data-main 屬性是一個特殊屬性,require.js 會檢查此屬性以開始載入指令碼
<!--when require.js loads it will inject another script tag
(with async attribute) for scripts/main.js-->
<script data-main="scripts/main" src="scripts/require.js"></script>
您通常會使用 data-main 指令碼來 設定組態選項,然後載入第一個應用程式模組。注意:require.js 為您的 data-main 模組產生的指令碼標籤包含 async 屬性。這表示您不能假設您的 data-main 指令碼的載入和執行會在同一個頁面中後續引用的其他指令碼之前完成。
例如,當 'foo' 模組的 require.config 路徑尚未設定,而後續又 require() 它時,這種安排會隨機失敗
<script data-main="scripts/main" src="scripts/require.js"></script>
<script src="scripts/other.js"></script>
// contents of main.js:
require.config({
paths: {
foo: 'libs/foo-1.1.3'
}
});
// contents of other.js:
// This code might be called before the require.config() in main.js
// has executed. When that happens, require.js will attempt to
// load 'scripts/foo.js' instead of 'scripts/libs/foo-1.1.3.js'
require(['foo'], function(foo) {
});
如果您想要在 HTML 頁面中執行 require()
呼叫,最好不要使用 data-main。data-main 僅適用於頁面只有一個主要進入點(data-main 指令碼)的情況。對於想要執行內嵌 require()
呼叫的頁面,最好將這些呼叫巢狀在組態的 require()
呼叫內
<script src="scripts/require.js"></script>
<script>
require(['scripts/config'], function() {
// Configuration loaded now, safe to do other require calls
// that depend on that config.
require(['foo'], function(foo) {
});
});
</script>
定義模組 § 1.3
模組與傳統的指令碼檔案不同,在於它定義了一個範圍良好的物件,避免污染全域命名空間。它可以明確列出其相依性,並取得這些相依性的控制權,而不需要參照全域物件,而是將相依性作為引數傳遞給定義模組的函式。RequireJS 中的模組是 模組模式 的延伸,其優點是不需要使用全域變數來參照其他模組。
RequireJS 模組語法讓它們可以盡可能快速載入,甚至可以不按順序載入,但會以正確的相依順序評估,而且由於不會建立全域變數,因此可以在 頁面中載入多個模組版本。
(如果您熟悉或正在使用 CommonJS 模組,請參閱 CommonJS 筆記,以了解 RequireJS 模組格式如何對應到 CommonJS 模組)。
磁碟上的每個檔案中只應該有一個模組定義。這些模組可以透過 最佳化工具 分組成最佳化的套件。
簡單的名稱/值對 § 1.3.1
如果模組沒有任何相依性,而且它只是名稱/值對的集合,則只需傳遞物件文字給 define()
//Inside file my/shirt.js:
define({
color: "black",
size: "unisize"
});
定義函式 § 1.3.2
如果模組沒有相依性,但需要使用函式來執行一些設定工作,則自行定義,傳遞函式給 define()
//my/shirt.js now does setup work
//before returning its module definition.
define(function () {
//Do setup work here
return {
color: "black",
size: "unisize"
}
});
具有相依性的定義函式§ 1.3.3
如果模組具有相依性,第一個引數應該是相依性名稱的陣列,第二個引數應該是定義函式。當所有相依性都載入後,將呼叫函式來定義模組。函式應該傳回定義模組的物件。相依性會以函式引數的形式傳遞給定義函式,其順序與相依性陣列中的順序相同
//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);
}
}
}
);
在此範例中,建立了一個 my/shirt 模組。它相依於 my/cart 和 my/inventory。在磁碟上,檔案結構如下
- my/cart.js
- my/inventory.js
- my/shirt.js
上述函式呼叫指定了兩個引數,「cart」和「inventory」。這些是由「./cart」和「./inventory」模組名稱所代表的模組。
函式不會在 my/cart 和 my/inventory 模組載入之前呼叫,而且函式會收到模組作為「cart」和「inventory」引數。
明確不建議定義全域變數的模組,以便頁面中可以同時存在多個模組版本(請參閱進階用法)。此外,函式引數的順序應與相依性的順序相符。
函式呼叫傳回的物件定義了「my/shirt」模組。透過這種方式定義模組,「my/shirt」不會存在為全域物件。
將模組定義為函式§ 1.3.4
模組不必傳回物件。函式中的任何有效傳回值都是允許的。以下是傳回函式作為其模組定義的模組
//A module definition inside foo/title.js. It uses
//my/cart and my/inventory modules from before,
//but since foo/title.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;
}
}
);
使用簡化的 CommonJS 包裝器定義模組§ 1.3.5
如果您希望重複使用以傳統 CommonJS 模組格式 編寫的程式碼,可能很難重新調整為上述使用的一系列相依性,而且您可能偏好相依性名稱與用於該相依性的區域變數直接對齊。在這些情況下,您可以使用 簡化的 CommonJS 包裝器
define(function(require, exports, module) {
var a = require('a'),
b = require('b');
//Return the module value
return function () {};
}
);
此包裝器仰賴 Function.prototype.toString() 提供函式內容的有用字串值。這在某些裝置上無法運作,例如 PS3 和一些較舊的 Opera 行動瀏覽器。使用 最佳化器 提取相依性,採用陣列格式,以便在這些裝置上使用。
更多資訊可在 CommonJS 頁面 上取得,以及 「Sugar」部分,在 Why AMD 頁面 上取得。
使用名稱定義模組§ 1.3.6
您可能會遇到一些 define() 呼叫,其中包含模組的名稱,作為 define() 的第一個引數
//Explicitly defines the "foo/title" module:
define("foo/title",
["my/cart", "my/inventory"],
function(cart, inventory) {
//Define foo/title object in here.
}
);
這些通常是由 最佳化工具 產生的。您可以自行明確命名模組,但這會讓模組的可攜性降低 -- 如果您將檔案移至另一個目錄,您將需要變更名稱。通常最好避免為模組編寫名稱,並讓最佳化工具燒錄模組名稱。最佳化工具需要新增名稱,以便可以在一個檔案中綑綁多個模組,以利於在瀏覽器中更快載入。
其他模組備註§ 1.3.7
每個檔案一個模組。:考量到模組名稱對檔案路徑查詢演算法的性質,每個 JavaScript 檔案應只定義一個模組。您應只使用 最佳化工具 將多個模組分組到最佳化的檔案中。
define() 內部的相對模組名稱:對於可能在 define() 函式呼叫內發生的 require("./relative/name") 呼叫,請務必要求 "require" 作為相依性,以便正確解析相對名稱
define(["require", "./relative/name"], function(require) {
var mod = require("./relative/name");
});
或者更好的是,使用可供 轉譯 CommonJS 模組使用的簡短語法
define(function(require) {
var mod = require("./relative/name");
});
此表單將使用 Function.prototype.toString() 尋找 require() 呼叫,並將其新增到相依性陣列中,連同 "require",因此程式碼將能正確使用相對路徑。
如果您在目錄內建立幾個模組,相對路徑非常有用,這樣您就可以與其他人或其他專案分享目錄,而且您希望能夠處理該目錄中的兄弟模組,而不需要知道目錄名稱。
相對模組名稱相對於其他名稱,而非路徑:載入器依其名稱儲存模組,而非其內部路徑。因此,對於相對名稱參照,這些名稱會相對於建立參照的模組名稱解析,然後該模組名稱或 ID 會轉換為路徑(如果需要載入)。「compute」套件的範例程式碼,其中包含「main」和「extras」模組
* lib/
* compute/
* main.js
* extras.js
其中 main.js 模組如下所示
define(["./extras"], function(extras) {
//Uses extras in here.
});
如果這是路徑設定
require.config({
baseUrl: 'lib',
paths: {
'compute': 'compute/main'
}
});
然後執行 require(['compute'])
,則 lib/compute/main.js 會具有「compute」的模組名稱。當它要求「./extras」時,會相對於「compute」解析,因此為「compute/./extras」,正規化後僅為「extras」。由於沒有該模組名稱的路徑設定,因此產生的路徑將為「lib/extras.js」,這是錯誤的。
對於這種情況,套件設定 是更好的選項,因為它允許將主模組設定為「compute」,但在內部,載入器會使用「compute/main」的 ID 儲存模組,以便「./extras」的相對參照正常運作。
另一個選項是在 lib/compute.js 建立一個模組,該模組僅為 define(['./compute/main'], function(m) { return m; });
,則不需要路徑或套件設定。
或者,不要設定路徑或套件設定,並將頂層要求呼叫設定為 require(['compute/main'])
。
產生相對於模組的 URL:您可能需要產生相對於模組的 URL。為此,請要求「require」作為相依性,然後使用 require.toUrl() 產生 URL
define(["require"], function(require) {
var cssUrl = require.toUrl("./style.css");
});
主控台除錯:如果您需要使用您已透過 JavaScript 主控台中的 require(["module/name"], function(){})
呼叫載入的模組,則可以使用僅使用模組字串名稱來擷取它的 require() 形式
require("module/name").callSomeFunction()
請注意,這僅在「module/name」先前透過 require 的非同步版本載入時才有效:require(["module/name"])
。如果使用相對路徑,例如「./module/name」,則這些路徑僅在定義內有效
循環相依性§ 1.3.8
如果您定義一個循環相依性(「a」需要「b」,而「b」需要「a」),則在這種情況下,當呼叫「b」的模組函式時,它將取得「a」的未定義值。「b」可以在模組定義後使用 require() 方法擷取「a」(請務必指定 require 作為相依性,以便使用正確的內容來查詢「a」)
//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() 來取得模組,而應該依賴於作為參數傳遞到函式的模組。循環依賴很少見,而且通常表示你可能想要重新考慮設計。然而,有時它們是必要的,在這種情況下,請如上所述使用 require()。
如果你熟悉 CommonJS 模組,你可以改用 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();
};
});
或者,如果你使用依賴陣列方法,請詢問特殊 'exports' 依賴關係:
//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();
};
});
指定 JSONP 服務依賴關係§ 1.3.9
JSONP 是一種在 JavaScript 中呼叫某些服務的方法。它可以在網域之間運作,並且是一種透過指令碼標籤呼叫僅需要透過 HTTP GET 的服務的既定方法。
要在 RequireJS 中使用 JSONP 服務,請將「define」指定為回呼參數的值。這表示你可以取得 JSONP URL 的值,就像它是模組定義一樣。
以下是一個呼叫 JSONP API 端點的範例。在此範例中,JSONP 回呼參數稱為「callback」,因此「callback=define」告訴 API 將 JSON 回應包裝在「define()」包裝器中
require(["http://example.com/api/data.json?callback=define"],
function (data) {
//The data object will be the API response for the
//JSONP data call.
console.log(data);
}
);
這種 JSONP 的使用應限於用於初始應用程式設定的 JSONP 服務。如果 JSONP 服務逾時,表示你透過 define() 定義的其他模組可能無法執行,因此錯誤處理並非穩健。
僅支援 JSONP 回傳值為 JSON 物件。陣列、字串或數字的 JSONP 回應將無法運作。
此功能不應使用於長輪詢 JSONP 連線,即處理即時串流的 API。此類 API 應於收到每個回應後執行更多腳本清理,而 RequireJS 只會擷取一次 JSONP URL,後續在 require() 或 define() 呼叫中使用相同 URL 作為相依項時,將會取得快取值。
載入 JSONP 服務時產生的錯誤通常會透過服務逾時浮現,因為載入腳本標籤並未提供太多網路問題的詳細資料。若要偵測錯誤,您可以覆寫 requirejs.onError() 以取得錯誤。詳細資訊請參閱 處理錯誤 區段。
取消定義模組§ 1.3.10
有一個全域函式 requirejs.undef(),可取消定義模組。它會重設載入器的內部狀態,以遺忘模組先前的定義。
不過,它不會從已定義的其他模組中移除模組,這些模組已取得該模組的控制權,並在執行時將其視為相依項。因此,它實際上僅適用於錯誤情況,即沒有其他模組取得模組值的控制權,或作為可能使用該模組的任何未來模組載入的一部分。請參閱 errback 區段 以取得範例。
如果您想針對取消定義工作進行更精密的相依項圖形分析,半私有的 onResourceLoad API 可能會有幫助。
機制 § 2
RequireJS 使用 head.appendChild() 將每個相依項載入為腳本標籤。
RequireJS 會等到所有相依項載入,找出呼叫定義模組函式的正確順序,然後在這些函式的相依項已呼叫後,呼叫模組定義函式。請注意,由於其子相依項關係和網路載入順序,給定模組定義函式的相依項可以按任何順序呼叫。
在具有同步載入的伺服器端 JavaScript 環境中使用 RequireJS 應該就像重新定義 require.load() 一樣容易。建置系統會執行此操作,該環境的 require.load 方法可以在 build/jslib/requirePatch.js 中找到。
未來,此程式碼可能會作為選用模組納入 require/ 目錄,您可以在 env 中載入此模組,以根據主機環境取得正確的載入行為。
組態選項 § 3
在頂層 HTML 頁面(或未定義模組的頂層腳本檔)中使用 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>
您也可以從 data-main 進入點 呼叫 require.config,但請注意 data-main 腳本會非同步載入。避免其他錯誤假設 data-main 及其 require.config 永遠會在腳本載入之前執行的進入點腳本。
此外,您可以在 require.js 載入之前將組態物件定義為全域變數 require
,並自動套用值。此範例指定一些依賴項,以便在 require.js 定義 require() 時立即載入
<script>
var require = {
deps: ["some/module1", "my/module2", "a.js", "b.js"],
callback: function(module1, module2) {
//This function will be called when all the dependencies
//listed above in deps are loaded. Note that this
//function could be called before the page is loaded.
//This callback is optional.
}
};
</script>
<script src="scripts/require.js"></script>
注意:最好使用 var require = {}
,不要使用 window.require = {}
,它在 IE 中無法正常運作。
有一些 模式可以將組態與主模組載入分開。
支援的組態選項
baseUrl:用於所有模組查詢的根路徑。因此,在上述範例中,「my/module」的腳本標籤將具有 src="/another/path/my/module.js」。在載入純 .js 檔時(由依賴項字串表示,以斜線開頭、有協定或以 .js 結尾),不會使用 baseUrl,這些字串會原樣使用,因此 a.js 和 b.js 將從包含上述片段的 HTML 頁面中載入。
如果組態中未明確設定 baseUrl,預設值將會是載入 require.js 的 HTML 頁面位置。如果使用了 data-main 屬性,該路徑將成為 baseUrl。
baseUrl 可以是與將載入 require.js 的頁面不同網域的 URL。RequireJS 腳本載入可以在不同網域之間運作。唯一的限制是 text! 外掛程式載入的文字內容:這些路徑至少在開發期間應該與頁面在同一個網域。最佳化工具會將 text! 外掛程式資源內嵌,因此在使用最佳化工具後,您可以使用從其他網域參考 text! 外掛程式資源的資源。
paths:未在 baseUrl 下直接找到的模組名稱路徑對應。路徑設定假設相對於 baseUrl,除非 paths 設定以「/」開頭或包含 URL 協定(「例如 http:」)。使用上述範例組態,「some/module」的腳本標籤將會是 src="/another/path/some/v1.0/module.js」。
用於模組名稱的路徑不應包含副檔名,因為路徑對應可能是目錄。路徑對應程式碼在將模組名稱對應到路徑時,會自動加上 .js 副檔名。如果使用了 require.toUrl(),它會加上適當的副檔名,如果它是文字範本之類的東西。
在瀏覽器中執行時,可以指定 路徑備援,以允許嘗試從 CDN 位置載入,但如果 CDN 位置載入失敗,則備援到本地位置。
bundles:在 RequireJS 2.1.10 中引入:允許將多個模組 ID 組態為在另一個腳本中找到。範例
requirejs.config({
bundles: {
'primary': ['main', 'util', 'text', 'text!template.html'],
'secondary': ['text!secondary.html']
}
});
require(['util', 'text'], function(util, text) {
//The script for module ID 'primary' was loaded,
//and that script included the define()'d
//modules for 'util' and 'text'
});
該設定指出:模組「main」、「util」、「text」和「text!template.html」將透過載入模組 ID「primary」來找到。模組「text!secondary.html」則可透過載入模組 ID「secondary」來找到。
這僅設定在包含多個 define() 模組的腳本中尋找模組的位置。它並未自動將這些模組繫結到套件的模組 ID。套件的模組 ID 僅用於尋找模組組。
使用路徑設定也可以做到類似的事情,但會更冗長,而且路徑設定路徑不允許其設定中出現載入器外掛程式資源 ID,因為路徑設定值是路徑區段,而非 ID。
如果執行建置,而且建置目標並非現有模組 ID,或者在已建置的 JS 檔案中包含不應由載入器外掛程式載入的載入器外掛程式資源,則套件設定會很有用。請注意,金鑰和值是模組 ID,而非路徑區段。它們是絕對模組 ID,而非模組 ID 前綴,例如 路徑設定 或 對應設定。此外,套件設定與對應設定不同,在於對應設定是一對一的模組 ID 關係,而套件設定則是將多個模組 ID 指向套件的模組 ID。
從 RequireJS 2.2.0 開始,最佳化器可以產生套件設定並將其插入頂層 requirejs.config() 呼叫。請參閱 bundlesConfigOutFile 建置設定選項以取得更多詳細資料。
shim:設定舊式傳統「瀏覽器全域變數」腳本的相依性、匯出和自訂初始化,這些腳本不使用 define() 來宣告相依性和設定模組值。
以下是一個範例。它需要 RequireJS 2.1.0 以上版本,並假設 backbone.js、underscore.js 和 jquery.js 已安裝在 baseUrl 目錄中。如果不是,則您可能需要為它們設定路徑設定
requirejs.config({
//Remember: only use shim config for non-AMD scripts,
//scripts that do not already call define(). The shim
//config will not work correctly if used on AMD scripts,
//in particular, the exports and init config will not
//be triggered, and the deps config will be confusing
//for those cases.
shim: {
'backbone': {
//These script dependencies should be loaded before loading
//backbone.js
deps: ['underscore', 'jquery'],
//Once loaded, use the global 'Backbone' as the
//module value.
exports: 'Backbone'
},
'underscore': {
exports: '_'
},
'foo': {
deps: ['bar'],
exports: 'Foo',
init: function (bar) {
//Using a function allows you to call noConflict for
//libraries that support it, and do other cleanup.
//However, plugins for those libraries may still want
//a global. "this" for the function will be the global
//object. The dependencies will be passed in as
//function arguments. If this function returns a value,
//then that value is used as the module export value
//instead of the object found via the 'exports' string.
//Note: jQuery registers as an AMD module via define(),
//so this will not work for jQuery. See notes section
//below for an approach for jQuery.
return this.Foo.noConflict();
}
}
}
});
//Then, later in a separate file, call it 'MyModel.js', a module is
//defined, specifying 'backbone' as a dependency. RequireJS will use
//the shim config to properly load 'backbone' and give a local
//reference to this module. The global Backbone will still exist on
//the page too.
define(['backbone'], function (Backbone) {
return Backbone.Model.extend({});
});
在 RequireJS 2.0.* 中,shim 設定中的「exports」屬性可以是函式,而非字串。在這種情況下,它的功能與上方所示的「init」屬性相同。「init」模式用於 RequireJS 2.1.0 以上版本,因此 exports
的字串值可用於 enforceDefine,但在已知程式庫已載入後,允許執行功能。
對於僅為 jQuery 或 Backbone 外掛程式且不需要匯出任何模組值的「模組」,shim 設定可以僅為相依性的陣列
requirejs.config({
shim: {
'jquery.colorize': ['jquery'],
'jquery.scroll': ['jquery'],
'backbone.layoutmanager': ['backbone']
}
});
不過,請注意,如果您想要在 IE 中取得 404 載入偵測,以便您可以使用路徑替代或 errback,則應提供字串 exports 值,以便載入器可以檢查腳本是否實際載入(init 的回傳值不用於 enforceDefine
檢查)
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'
}
}
});
「shim」設定的重要注意事項
- shim 設定僅設定程式碼關係。若要載入屬於或使用 shim 設定的模組,需要正常的 require/define 呼叫。單獨設定 shim 不會觸發程式碼載入。
- 僅將其他「shim」模組用作 shim 腳本的相依性,或沒有相依性且在建立全域變數後呼叫 define() 的 AMD 函式庫(例如 jQuery 或 lodash)。否則,如果您將 AMD 模組用作 shim 設定模組的相依性,則在建置後,該 AMD 模組可能在建置中的 shim 程式碼執行後才會評估,且會發生錯誤。最終的解決方法是升級所有 shim 程式碼,使其具有選擇性的 AMD define() 呼叫。
- 如果無法升級 shim 程式碼以使用 AMD define() 呼叫,則自 RequireJS 2.1.11 起,最佳化程式有一個 wrapShim 建置選項,它會嘗試在建置中自動將 shim 程式碼包覆在 define() 中。這會變更 shim 相依性的範圍,因此無法保證總是有效,但例如,對於相依於 AMD 版本 Backbone 的 shim 相依性,它可能會有幫助。
- init 函式不會對 AMD 模組呼叫。例如,您無法使用 shim init 函式呼叫 jQuery 的 noConflict。請參閱 對應模組以使用 noConflict,以取得 jQuery 的替代方法。
- 透過 RequireJS 在節點中執行 AMD 模組時,不支援 shim 設定(但適用於最佳化程式使用)。視要進行 shim 的模組而定,它可能會在節點中失敗,因為節點沒有與瀏覽器相同的全域環境。自 RequireJS 2.1.7 起,它會在主控台中警告您不支援 shim 設定,且可能運作或不運作。如果您想要抑制該訊息,您可以傳遞
requirejs.config({ suppress: { nodeShim: true }});
。
「shim」設定的重要最佳化程式注意事項:
- 您應該使用 mainConfigFile 建置選項 來指定要在哪個檔案中尋找 shim 設定。否則,最佳化程式將不知道 shim 設定。另一個選項是在建置設定檔中複製 shim 設定。
- 請勿在建置中將 CDN 載入與 shim 設定混用。範例場景:您從 CDN 載入 jQuery,但使用 shim 設定載入類似 Backbone 庫版本的東西,而它仰賴 jQuery。當您執行建置時,請務必將 jQuery 內嵌於建置檔案中,並不要從 CDN 載入。否則,Backbone 將會內嵌於建置檔案中,而且它會在 CDN 載入的 jQuery 載入之前執行。這是因為 shim 設定只會延遲載入檔案,直到載入相依項為止,但不會自動包裝 define。在建置之後,相依項已經內嵌,shim 設定無法延遲非 define() 的程式碼執行。define() 的模組在建置後會與 CDN 載入的程式碼一起運作,因為它們會適當地將其來源包裝在 define 工廠函式中,而該函式不會在載入相依項之前執行。因此,教訓是:shim 設定是針對非模組化程式碼、舊程式碼的權宜之計。define() 的模組會更好。
- 對於本機的多檔案建置,上述 CDN 建議也適用。對於任何 shim 腳本,其相依項必須在 shim 腳本執行之前載入。這表示在包含 shim 腳本的建置層中直接建置其相依項,或使用
require([], function (){})
呼叫載入其相依項,然後對具有 shim 腳本的建置層執行巢狀require([])
呼叫。 - 如果您使用 uglifyjs 壓縮程式碼,請勿將 uglify 選項
toplevel
設為 true,或是在使用命令列時請勿傳遞-mt
。該選項會混淆 shim 用於尋找匯出的全域名稱。
map:對於指定的模組前綴,取代載入具有指定 ID 的模組,替換為不同的模組 ID。
這種功能對於可能具有兩組模組的大型專案而言非常重要,這些模組可能需要使用兩個不同的「foo」版本,但它們仍然需要彼此合作。
這無法使用 背景支援的多版本支援 執行。此外,路徑設定 只用於設定模組 ID 的根路徑,而不是用於將一個模組 ID 對應至另一個模組 ID。
map 範例
requirejs.config({
map: {
'some/newmodule': {
'foo': 'foo1.2'
},
'some/oldmodule': {
'foo': 'foo1.0'
}
}
});
如果模組在磁碟上配置如下
- foo1.0.js
- foo1.2.js
- some/
- newmodule.js
- oldmodule.js
當「some/newmodule」執行 `require('foo')` 時,它會取得 foo1.2.js 檔案,而當「some/oldmodule」執行 `require('foo')` 時,它會取得 foo1.0.js 檔案。
此功能只適用於呼叫 define() 並註冊為匿名模組的真正 AMD 模組。此外,僅對 map 設定使用絕對模組 ID。相對 ID(例如 '../some/thing'
)無法使用。
也支援「*」map 值,這表示「對於所有載入的模組,請使用此 map 設定」。如果存在更明確的 map 設定,則該設定會優先於星號設定。範例
requirejs.config({
map: {
'*': {
'foo': 'foo1.2'
},
'some/oldmodule': {
'foo': 'foo1.0'
}
}
});
表示對於「some/oldmodule」以外的任何模組,當需要「foo」時,改用「foo1.2」。僅針對「some/oldmodule」,當它需要「foo」時,改用「foo1.0」。
注意:在使用地圖設定進行建置時,必須將地圖設定提供給最佳化器,而建置輸出仍必須包含設定地圖設定的 requirejs 設定呼叫。最佳化器不會在建置期間變更 ID,因為專案中的一些相依性參考可能取決於執行階段變數狀態。因此,最佳化器不會在建置後使地圖設定無效。
config:通常需要將設定資訊傳遞給模組。該設定資訊通常是應用程式的一部分,而且需要有方法將其傳遞給模組。在 RequireJS 中,這是透過 requirejs.config() 的 config 選項來完成。然後,模組可以透過要求特殊相依性「module」並呼叫 module.config() 來讀取該資訊。範例
requirejs.config({
config: {
'bar': {
size: 'large'
},
'baz': {
color: 'blue'
}
}
});
//bar.js, which uses simplified CJS wrapping:
//https://requirejs.dev.org.tw/docs/whyamd.html#sugar
define(function (require, exports, module) {
//Will be the value 'large'
var size = module.config().size;
});
//baz.js which uses a dependency array,
//it asks for the special module ID, 'module':
//https://github.com/requirejs/requirejs/wiki/Differences-between-the-simplified-CommonJS-wrapper-and-standard-AMD-define#wiki-magic
define(['module'], function (module) {
//Will be the value 'blue'
var color = module.config().color;
});
若要將設定傳遞給 套件,請針對套件中的主模組,而不是套件 ID
requirejs.config({
//Pass an API key for use in the pixie package's
//main module.
config: {
'pixie/index': {
apiKey: 'XJKDLNS'
}
},
//Set up config for the "pixie" package, whose main
//module is the index.js file in the pixie folder.
packages: [
{
name: 'pixie',
main: 'index'
}
]
});
packages:設定從 CommonJS 套件載入模組。請參閱 套件主題 以取得更多資訊。
nodeIdCompat:Node 將模組 ID example.js
和 example
視為相同。預設情況下,這兩個是 RequireJS 中不同的 ID。如果您最終使用從 npm 安裝的模組,則可能需要將此設定值設為 true
以避免解析問題。此選項僅適用於不同處理「.js」字尾,它不會執行任何其他節點解析和評估比對,例如 .json 檔案處理(JSON 處理無論如何都需要「json!」載入器外掛程式)。在 2.1.10 及更新版本中提供。
waitSeconds:放棄載入腳本前的等待秒數。將其設為 0 會停用逾時。預設為 7 秒。
context:提供給載入內容的名稱。這允許 require.js 在頁面中載入多個版本的模組,只要每個頂層 require 呼叫指定唯一的內容字串即可。若要正確使用它,請參閱 多版本支援 區段。
deps:要載入的相依性陣列。當在載入 require.js 之前將 require 定義為組態物件時很有用,而且您想要在定義 require() 之後立即指定要載入的相依性。使用 deps 就如同執行 require([])
呼叫,但只要載入器處理完組態就會執行。它不會封鎖任何其他 require() 呼叫開始其對模組的要求,它只是一個方法,用於指定一些模組要作為組態區塊的一部分非同步載入。
callback:在載入 deps 之後要執行的函式。當在載入 require.js 之前將 require 定義為組態物件時很有用,而且您想要在載入組態的 deps 陣列之後指定一個 require 函式。
enforceDefine:如果設定為 true,則會在載入未呼叫 define() 或具有可檢查的 shim exports 字串值的指令碼時擲回錯誤。請參閱 在 IE 中捕捉載入失敗 以取得更多資訊。
xhtml:如果設定為 true,則會使用 document.createElementNS() 來建立指令碼元素。
urlArgs:附加到 RequireJS 用來擷取資源的 URL 的額外查詢字串引數。在瀏覽器或伺服器未正確組態時,最有用於快取清除。urlArgs 的快取清除設定範例
urlArgs: "bust=" + (new Date()).getTime()
自 RequireJS 2.2.0 起,urlArgs 可以是函式。如果為函式,它會接收模組 ID 和 URL 作為參數,而且應該傳回一個字串,該字串會新增到 URL 的結尾。如果沒有引數,請傳回一個空白字串。務必小心在 URL 的現有狀態下新增「?」或「&」。範例
requirejs.config({
urlArgs: function(id, url) {
var args = 'v=1';
if (url.indexOf('view.html') !== -1) {
args = 'v=2'
}
return (url.indexOf('?') === -1 ? '?' : '&') + args;
}
});
在開發期間,這可能會很有用,但務必在部署您的程式碼之前將其移除。
scriptType:指定 RequireJS 插入到文件中的 script 標籤所使用的 type="" 屬性的值。預設為「text/javascript」。若要使用 Firefox 的 JavaScript 1.8 功能,請使用「text/javascript;version=1.8」。
skipDataMain:在 RequireJS 2.1.9 中引入:如果設定為 true
,則會略過 data-main 屬性掃描,該掃描用於開始載入模組。如果 RequireJS 嵌入在可能與頁面上的其他 RequireJS 函式庫互動的公用程式函式庫中,而且嵌入版本不應該執行 data-main 載入,則很有用。
進階用法 § 4
從套件載入模組§ 4.1
RequireJS 支援載入位於 CommonJS 套件 目錄結構中的模組,但需要指定一些額外的組態才能運作。具體來說,支援下列 CommonJS 套件功能
- 套件可以與模組名稱/前綴關聯。
- 套件組態可以為特定套件指定下列屬性
- name:套件名稱(用於模組名稱/前綴對應)
- location:磁碟上的位置。位置相對於 baseUrl 組態值,除非它們包含協定或以正斜線 (/) 開頭。
- main:套件中應在有人對「packageName」執行 require 時使用的模組名稱。預設值為「main」,因此僅在與預設值不同時指定它。此值相對於套件資料夾。
重要事項
- 雖然套件可以採用 CommonJS 目錄配置,但模組本身應採用 RequireJS 可以理解的模組格式。規則例外:如果您使用 r.js Node 轉接器,則模組可以採用傳統的 CommonJS 模組格式。如果您需要將傳統 CommonJS 模組轉換成 RequireJS 使用的非同步模組格式,可以使用 CommonJS 轉換器工具。
- 專案內容中一次只能使用一個套件版本。您可以使用 RequireJS 多版本支援 載入兩個不同的模組內容,但如果您想在一個內容中使用套件 A 和 B,而它們依賴於套件 C 的不同版本,則會產生問題。這可能會在未來有所改變。
如果您使用 入門指南 中指定的類似專案配置,則網路專案的開頭看起來會像這樣(基於 Node/Rhino 的專案類似,只需將 scripts 目錄的內容用作頂層專案目錄)
- project-directory/
- project.html
- scripts/
- require.js
以下是範例目錄配置,其中包含兩個套件,cart 和 store
- project-directory/
- project.html
- scripts/
- cart/
- main.js
- store/
- main.js
- util.js
- main.js
- require.js
- cart/
project.html 會有類似這樣的 script 標籤
<script data-main="scripts/main" src="scripts/require.js"></script>
這將指示 require.js 載入 scripts/main.js。main.js 使用「套件」設定來設定相對於 require.js 的套件,在這個案例中是來源套件「cart」和「store」
//main.js contents
//Pass a config object to require
require.config({
"packages": ["cart", "store"]
});
require(["cart", "store", "store/util"],
function (cart, store, util) {
//use the modules as usual.
});
require「cart」表示它將從 scripts/cart/main.js 載入,因為「main」是 RequireJS 支援的預設主模組設定。require「store/util」將從 scripts/store/util.js 載入。
如果「store」套件沒有遵循「main.js」慣例,而且看起來更像這樣
- project-directory/
- project.html
- scripts/
- cart/
- main.js
- store/
- store.js
- util.js
- main.js
- package.json
- require.js
- cart/
那麼 RequireJS 組態將會看起來像這樣
require.config({
packages: [
"cart",
{
name: "store",
main: "store"
}
]
});
為了避免冗長,強烈建議在結構中始終使用套件,這些套件在其結構中使用「main」慣例。
多版本支援§ 4.2
如 組態選項 中所述,透過使用不同的「內容」組態選項,可以在一個頁面中載入模組的多個版本。require.config() 傳回一個 require 函式,它將使用內容組態。以下是一個範例,它載入 alpha 和 beta 模組的兩個不同版本(此範例取自其中一個測試檔案)
<script src="../require.js"></script>
<script>
var reqOne = require.config({
context: "version1",
baseUrl: "version1"
});
reqOne(["require", "alpha", "beta",],
function(require, alpha, beta) {
log("alpha version is: " + alpha.version); //prints 1
log("beta version is: " + beta.version); //prints 1
setTimeout(function() {
require(["omega"],
function(omega) {
log("version1 omega loaded with version: " +
omega.version); //prints 1
}
);
}, 100);
});
var reqTwo = require.config({
context: "version2",
baseUrl: "version2"
});
reqTwo(["require", "alpha", "beta"],
function(require, alpha, beta) {
log("alpha version is: " + alpha.version); //prints 2
log("beta version is: " + beta.version); //prints 2
setTimeout(function() {
require(["omega"],
function(omega) {
log("version2 omega loaded with version: " +
omega.version); //prints 2
}
);
}, 100);
});
</script>
請注意,「require」被指定為模組的相依項。這允許傳遞給函式回呼的 require() 函式使用正確的內容來正確載入模組以支援多版本。如果「require」未指定為相依項,則可能會發生錯誤。
在頁面載入後載入程式碼§ 4.3
多版本支援 區段中的上述範例顯示了如何透過巢狀 require() 呼叫在稍後載入程式碼。
Web Worker 支援§ 4.4
從 0.12 版開始,RequireJS 可以執行在 Web Worker 內。只要在 Web Worker 內使用 importScripts() 來載入 require.js(或包含 require() 定義的 JS 檔案),然後呼叫 require 即可。
你可能需要設定 baseUrl 組態選項,以確保 require() 可以找到要載入的腳本。
你可以透過查看 單元測試 中使用的其中一個檔案來查看它的使用範例。
Rhino 支援§ 4.5
RequireJS 可以透過 r.js 介接器 在 Rhino 中使用。請參閱 r.js README 以取得更多資訊。
Nashorn 支援§ 4.6
從 RequireJS 2.1.16 開始,RequireJS 可透過 r.js 適配器,在 Nashorn(Java 8+ 的 JavaScript 引擎)中使用。請參閱 r.js README 以取得更多資訊。
錯誤處理§ 4.7
一般類型的錯誤為腳本的 404(找不到)、網路逾時或載入的腳本中的錯誤。RequireJS 有幾個工具可處理這些錯誤:require 特定的 errback、「paths」陣列設定檔和全域 requirejs.onError。
傳遞給 errback 和全域 requirejs.onError 函式的錯誤物件通常會包含兩個自訂屬性
- requireType:包含一般分類的字串值,例如「timeout」、「nodefine」、「scripterror」。
- requireModules:逾時的模組名稱/URL 陣列。
如果您收到包含 requireModules 的錯誤,這可能表示依賴於 requireModules 陣列中模組的其他模組未定義。
在 IE 中捕捉載入失敗 § 4.6.1
Internet Explorer 有一組問題,使得難以偵測 errback/paths 回退的載入失敗
- script.onerror 在 IE 6-8 中不起作用。沒有辦法知道載入腳本是否會產生 404,更糟的是,即使在 404 的情況下,它也會觸發 onreadystatechange,並顯示完成狀態。
- script.onerror 在 IE 9+ 中起作用,但它有一個錯誤,在執行腳本後不會立即觸發 script.onload 事件處理常式,因此它無法支援允許匿名 AMD 模組的標準方法。因此,仍使用 script.onreadystatechange。但是,onreadystatechange 會在 script.onerror 函式觸發前,以完成狀態觸發。
因此,對於 IE 來說,同時允許匿名 AMD 模組(這是 AMD 模組的核心優點)和可靠地偵測錯誤是非常困難的。
但是,如果您在專案中知道使用 define() 宣告所有模組,或使用 shim 設定檔為任何不使用 define() 的項目指定字串匯出,那麼如果您將 enforceDefine 設定檔值設為 true,則載入器可以確認腳本載入,方法是檢查 define() 呼叫或 shim 的匯出全域值是否存在。
因此,如果您想要支援 Internet Explorer、捕捉載入錯誤,並透過直接 define() 呼叫或 shim 設定檔取得模組化程式碼,請務必將 enforceDefine 設為 true。請參閱下一節的範例。
注意:如果您設定 enforceDefine: true,並使用 data-main="" 載入您的主 JS 模組,則該主 JS 模組必須呼叫 define(),而不是 require() 來載入它需要的程式碼。主 JS 模組仍可以使用 require/requirejs 設定設定檔值,但它應該使用 define() 來載入模組。
如果您接著也使用 almond 在沒有 require.js 的情況下建置您的程式碼,請務必使用 insertRequire 建置設定,以插入主模組的 require 呼叫 -- 這與 data-main 所做的初始 require() 呼叫有相同目的。
require([]) errback § 4.6.2
當與 requirejs.undef() 搭配使用時,Errback 能讓您偵測模組載入失敗,取消定義該模組,將設定重設至另一個位置,然後再試一次。
常見的用例是使用 CDN 托管的函式庫版本,但如果失敗,則切換為在本地端載入檔案
requirejs.config({
enforceDefine: true,
paths: {
jquery: 'http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min'
}
});
//Later
require(['jquery'], function ($) {
//Do something with $ here
}, function (err) {
//The errback, error callback
//The error has a list of modules that failed
var failedId = err.requireModules && err.requireModules[0];
if (failedId === 'jquery') {
//undef is function only on the global requirejs object.
//Use it to clear internal knowledge of jQuery. Any modules
//that were dependent on jQuery and in the middle of loading
//will not be loaded yet, they will wait until a valid jQuery
//does load.
requirejs.undef(failedId);
//Set the path to jQuery to local path
requirejs.config({
paths: {
jquery: 'local/jquery'
}
});
//Try again. Note that the above require callback
//with the "Do something with $ here" comment will
//be called if this new attempt to load jQuery succeeds.
require(['jquery'], function () {});
} else {
//Some other error. Maybe show message to the user.
}
});
使用 `requirejs.undef()`,如果您稍後設定不同的設定並嘗試載入相同的模組,載入器仍會記住哪些模組需要該相依性,並在新設定的模組載入時完成載入。
注意:errback 僅適用於回呼式 require 呼叫,不適用於 define() 呼叫。define() 僅用於宣告模組。
paths 設定備援 § 4.6.3
上述偵測載入失敗、取消定義模組、修改路徑和重新載入的模式是一個相當常見的要求,因此也有簡寫法。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 的情況。這與可以套用至模組 ID 前綴區段任何部分的正常 paths 設定不同。備援更針對異常錯誤復原,而不是一般的路徑搜尋路徑解決方案,因為這些解決方案在瀏覽器中效率不彰。
全域 requirejs.onError 函式 § 4.6.4
若要偵測未由本機 errback 捕捉到的錯誤,您可以覆寫 requirejs.onError()
requirejs.onError = function (err) {
console.log(err.requireType);
if (err.requireType === 'timeout') {
console.log('modules: ' + err.requireModules);
}
throw err;
};
載入器外掛程式 § 5
RequireJS 支援 載入器外掛程式。這是一種支援相依性的方法,這些相依性並非一般 JS 檔案,但仍對於腳本在執行工作之前載入非常重要。RequireJS wiki 有 外掛程式清單。本節說明 RequireJS 隨附維護的一些特定外掛程式
指定文字檔相依性§ 5.1
使用一般 HTML 標籤來建構 HTML 很棒,而不是在腳本中建構 DOM 結構。然而,沒有好的方法可以在 JavaScript 檔案中嵌入 HTML。能做到的最好方法是使用 HTML 字串,但這可能很難管理,特別是對於多行 HTML。
RequireJS 有個外掛程式 text.js,可以協助處理這個問題。如果在相依項中使用 text! 前綴,它會自動載入。請參閱 text.js README 以取得更多資訊。
網頁載入事件支援/DOM 準備就緒§ 5.2
使用 RequireJS 載入指令碼時,有可能在 DOM 準備就緒前就已完成。任何嘗試與 DOM 互動的工作都應該等到 DOM 準備就緒。對於現代瀏覽器,這是透過等待 DOMContentLoaded 事件來完成的。
然而,並非所有瀏覽器都支援 DOMContentLoaded。domReady 模組實作了一個跨瀏覽器方法來判斷 DOM 何時準備就緒。 下載模組 並在專案中使用,如下所示
require(['domReady'], function (domReady) {
domReady(function () {
//This function is called once the DOM is ready.
//It will be safe to query the DOM and manipulate
//DOM nodes in this function.
});
});
由於 DOM 準備就緒是一個常見的應用程式需求,理想上可以避免在上述 API 中使用巢狀函式。domReady 模組也實作了 載入器外掛程式 API,因此您可以使用載入器外掛程式語法(注意 domReady 相依項中的 !)來強制 require() 回呼函式在執行前等待 DOM 準備就緒。
domReady當用作載入器外掛程式時,將傳回目前的的文件
require(['domReady!'], function (doc) {
//This function is called once the DOM is ready,
//notice the value for 'domReady!' is the current
//document.
});
注意:如果文件載入需要一段時間(可能是非常大的文件,或具有載入大型 JS 檔案的 HTML 指令碼標籤,在完成之前會阻擋 DOM 完成),使用 domReady 作為載入器外掛程式可能會導致 RequireJS 「逾時」錯誤。如果這是一個問題,請增加 waitSeconds 設定,或僅將 domReady 用作模組,並在 require() 回呼中呼叫 domReady()。
定義 I18N 捆綁§ 5.3
一旦您的網路應用程式達到一定的規模和知名度,在地化介面中的字串並提供其他特定地區的資訊就會變得更有用。然而,制定一個能很好地支援多個地區設定的方案可能會很麻煩。
RequireJS 讓您可以設定一個具有在地化資訊的基本模組,而無需強迫您預先提供所有特定地區設定的資訊。它可以隨著時間新增,而且只有在不同地區設定之間變更的字串/值才能定義在特定地區設定的文件中。
i18n.js 外掛程式提供 i18n 軟體包支援。當模組或相依項指定 i18n! 前綴時,它會自動載入(詳情請見下方)。下載外掛程式,並將它放在與應用程式主 JS 檔案相同的目錄中。
若要定義軟體包,請將它放在名為「nls」的目錄中,i18n! 外掛程式假設名稱中含有「nls」的模組名稱表示 i18n 軟體包。名稱中的「nls」標記告訴 i18n 外掛程式在哪裡可以找到地區目錄(它們應該是 nls 目錄的直接子目錄)。如果您想在「my」模組集中提供一組顏色名稱,請建立下列目錄結構
- my/nls/colors.js
該檔案的內容應如下所示
//my/nls/colors.js contents:
define({
"root": {
"red": "red",
"blue": "blue",
"green": "green"
}
});
包含「root」屬性的物件文字定義此模組。這是您在後續在地化工作中必須執行的所有步驟。
然後,您可以在另一個模組中使用上述模組,例如在 my/lamps.js 檔案中
//Contents of my/lamps.js
define(["i18n!my/nls/colors"], function(colors) {
return {
testMessage: "The name for red in this locale is: " + colors.red
}
});
my/lamps 模組有一個名為「testMessage」的屬性,使用 colors.red 顯示顏色的在地化值。
稍後,當您想將特定翻譯新增到檔案時,例如 fr-fr 地區設定,請將 my/nls/colors 變更為如下所示
//Contents of my/nls/colors.js
define({
"root": {
"red": "red",
"blue": "blue",
"green": "green"
},
"fr-fr": true
});
然後在 my/nls/fr-fr/colors.js 中定義一個具有下列內容的檔案
//Contents of my/nls/fr-fr/colors.js
define({
"red": "rouge",
"blue": "bleu",
"green": "vert"
});
RequireJS 會使用瀏覽器的 navigator.languages、navigator.language 或 navigator.userLanguage 屬性來判斷要對 my/nls/colors 使用哪些地區設定值,因此您的應用程式不必變更。如果您偏好設定地區設定,可以使用模組設定將地區設定傳遞給外掛程式
requirejs.config({
config: {
//Set the config for the i18n
//module ID
i18n: {
locale: 'fr-fr'
}
}
});
請注意,為了避免大小寫問題,RequireJS 永遠會使用地區設定的小寫版本,因此磁碟上所有 i18n 軟體包的目錄和檔案都應使用小寫地區設定。
RequireJS 也夠聰明,可以挑選正確的地區設定軟體包,也就是與 my/nls/colors 提供的軟體包最相符的軟體包。例如,如果地區設定為「en-us」,則會使用「root」軟體包。如果地區設定為「fr-fr-paris」,則會使用「fr-fr」軟體包。
RequireJS 也會將軟體包組合在一起,因此,例如,如果法語軟體包定義如下所示(略去 red 的值)
//Contents of my/nls/fr-fr/colors.js
define({
"blue": "bleu",
"green": "vert"
});
然後「root」中的紅色值會被使用。這適用於所有地區設定片段。如果下列所有套件都已定義,RequireJS 會使用下列優先順序中的值(最上方的優先順序最高)
- my/nls/fr-fr-paris/colors.js
- my/nls/fr-fr/colors.js
- my/nls/fr/colors.js
- my/nls/colors.js
如果您偏好不將 root 套件包含在頂層模組中,您可以像一般的地區設定套件一樣定義它。在這種情況下,頂層模組會看起來像
//my/nls/colors.js contents:
define({
"root": true,
"fr-fr": true,
"fr-fr-paris": true
});
而 root 套件會看起來像
//Contents of my/nls/root/colors.js
define({
"red": "red",
"blue": "blue",
"green": "green"
});