1. 程式人生 > >Dojo1.11官方教程文件翻譯(2.2)AMD模組入門

Dojo1.11官方教程文件翻譯(2.2)AMD模組入門

2.2 AMD模組入門

Dojo支援模組以非同步模組定義(AMD)的格式寫入,這使得程式碼更容易編寫和除錯。在本教程中,我們將解釋AMD的基本理解和使用。
如果你正從低於1.7的版本進行遷移,本教程的1.8版本會比較有用,它提供一些從Dojo的舊模組系統向AMD遷移的指導。本教程只關注AMD。

概述

非同步模組定義(AMD)格式是Dojo從1.7版本開始摘取的模組格式。它為舊的Dojo模組風格提供了許多增強,包括完全非同步操作、真正的可移植性包、更好的依賴管理和對除錯支援的改善。這也是一個社群驅動的標準,就是說寫入模組的AMD規範可以使用任何其他的AMD-compliant載入器或庫。在本教程中,我們將解釋AMD並解釋如何使用它。

模組是什麼?

一個模組是一個可以由引用訪問的值。如果你想在一個模組裡展開多個數據或函式,它們必須是代表模組的單一物件的屬性。實際上來說,它為一個簡單的值多餘的建立了一個模組,例如var tinyModule = 'simple value'; ,但這是有效的。模組更多的意義在於將你的程式碼模組化,將它分解成處理特定功能的邏輯子集。如果你想用名字和地址這樣的資訊來待代表一個人,或者為你的人新增方法,把所有程式碼放在一個位置是很有意義的。在檔案系統中,一個模組儲存為一個單獨檔案。

如何建立一個模組

在AMD裡,你通過向載入器註冊來建立一個模組。
什麼是載入器?載入器就是定義和載入模組背後控制邏輯的程式碼(是的,只用Javascript)。當你可以通過載入 dojo.js

require.js 得到一個AMD載入器。載入器定義了互動函式,分別是require和define。
使用全域性函式define 可以通過載入器註冊一個模組,先看幾個例子:

define(5);

不是很複雜但是有用,這個模組的值是數字5。

define({
    library: 'dojo',
    version: 1.10
});

來個更有意思點的,這個模組載入的時候,能夠得到一個帶2個屬性的物件。

define(function(){
    var privateValue = 0;
    return {
        increment: function
(){
privateValue++; }, decrement: function(){ privateValue--; }, getValue: function(){ return privateValue; } }; });

這個例子裡,向define 傳遞了一個函式。這個函式已經評定並且結果被載入器儲存為一個模組。這段程式碼使用閉包建立了一個私有值,它不會被外部程式碼直接訪問到,但是可以通過物件提供的方法進行檢查和操作,這個物件作為模組的值返回。

如何載入模組?

首先,我們需要了解如何識別模組。為了載入模組,你需要一些識別它的方法。類似於其他程式語言的module/package系統,AMD模組通過它的路徑和檔名進行識別。讓我們把上面示例的程式碼儲存在一個資料夾裡:

app/counter.js

在加入一個載入器和index.html——應用接入點。檔案結構如下:

/
    index.html
    /dojo/
    /app/
        counter.js

index 頁面像這樣:

<html>
    <body>
        <script src="dojo/dojo.js" data-dojo-config="async: true"></script>
        <script>
            require([
                "app/counter"
            ], function(counter){
                log(counter.getValue());
                counter.increment();
                log(counter.getValue());
                counter.decrement();
                log(counter.getValue());
            });
        </script>
    </body>
</html>

下面回顧一下:

  1. app/counter.js 裡,我們呼叫define 用載入器註冊一個模組。注意我們定義的模組是一個物件的引用,不是一個建構函式,也就是說這個模組載入的每一部分程式碼都會引用相同的物件。總之,模組返回建構函式,但是在某些情況下他適當返回一個單例物件。
  2. 通過檔案系統定位我們的模組,它在包含著index.html的資料夾的一個子資料夾裡,這個子資料夾是AMD載入器(dojo/dojo.js)的兄弟資料夾。不需要我們額外配置,載入器知道module id“app/counter”意思是它應該載入app/counter.js 檔案,並將它的返回值作為一個模組。
  3. index.html 裡,我們呼叫require 來載入“app/counter”模組。你可以簡單地通過require(["app/counter"]) 載入模組。如果模組中的程式碼有其他副作用(比如擴增其他模組),你完全不需要再引用這些模組。不過,如果你需要一個模組的引用,你需要提供一個回撥函式。載入器會確保模組已經被載入,一旦載入完成,它會將傳遞給它的任意模組作為引數呼叫回撥函式。與任何其他函式一樣,你可以自由地為引數命名,沒有要求引數名要與模組名有關係。即便如此,使用和模組名相似的命名仍是一種比較好的做法。

模組載入模組

到目前為止,我們的例子只是展示了define函式的簡單運用。當一些結構清晰的模組組合成應用,這些模組之間自然有很多依賴關係。define 函式可以自動的為你的模組載入依賴關係模組。在模組生成之前要將依賴關係列表傳遞給 define .

define([
    "dojo/_base/declare",
    "dojo/dom",
    "app/dateFormatter"
], function(declare, dom, dateFormatter){
    return declare(null, {
        showDate: function(id, date){
            dom.byId(id).innerHTML = dateFormatter.format(date);
        }
    });
});

這個例子展示了AMD應用的一些特點:

  1. 多重依賴—— 依賴關係列表裡同時指定了”dojo/dom” 和 (假設的) “app/dateFormatter” 。
  2. 返回一個構造器——這個模組可以叫做”app/DateManager”這樣的名字。使用它的程式碼如下:
require([
    "app/DateManager"
], function(DateManager){
    var dm = new DateManager();
    dm.showDate('dateElementId', new Date());
});

在你用Dojo開發之前首先要熟悉的主題之一是AMD,還有一個重要功能是declare,如果你還沒有熟悉 dojo/_base/declare ,接下來可以先看看它的教程

使用外掛

除了常規模組,AMD載入器還有一種稱為外掛的新模組。外掛通過其超越簡單AMD模組的功能對載入器進行擴充套件。外掛的載入或多或少與常規模組一樣,不過在模組識別符號的末尾使用一個特殊符號“!”來標識它是一個外掛請求。“!”之後的資料會直接傳遞給外掛來處理。通過幾個例子來學習會比較清楚點。Dojo提供幾個預設外掛,最重要的四個是dojo/textdojo/i18ndojo/has、和dojo/domReady 。讓我們來看看如何使用它們。

當你需要中檔案(比如HTML模板)載入字串的時候可以使用dojo/text。 獲取的值會被快取起來,這樣後面再呼叫同一檔案的時候就不會再額外進行請求。生成器使用dojo/text載入內聯字串。例如為一個模板化的widget載入一個模板,你要像這樣定義你的模組:

// in "my/widget/NavBar.js"
define([
    "dojo/_base/declare",
    "dijit/_WidgetBase",
    "dijit/_TemplatedMixin",
    "dojo/text!./templates/NavBar.html"
], function(declare, _WidgetBase, _TemplatedMixin, template){
    return declare([_WidgetBase, _TemplatedMixin], {
        // template contains the content of the file "my/widget/templates/NavBar.html"
        templateString: template
    });
});

dojo/i18n 根據web瀏覽器的使用者語言環境載入語言包。示例:

// in "my/widget/Dialog.js"
define([
    "dojo/_base/declare",
    "dijit/Dialog",
    "dojo/i18n!./nls/common"
], function(declare, Dialog, i18n){
    return declare(Dialog, {
        title: i18n.dialogTitle
    });
});

Dojo載入器包含一個has.js實現的API特徵檢測器;dojo/has 外掛利用此功能有條件的載入模組。像下面這麼用:

// in "my/events.js"
define([
    "dojo/dom",
    "dojo/has!dom-addeventlistener?./events/w3c:./events/ie"
], function(dom, events){
    // events is "my/events/w3c" if the "dom-addeventlistener" test was true, "my/events/ie" otherwise
    events.addEvent(dom.byId("foo"), "click", function(){
        console.log("Foo clicked!");
    });
});

dojo/domReady用來替代dojo.ready。它是直到DOM準備好才執行的模組。像下面這麼用:

// in "my/app.js"
define(["dojo/dom", "dojo/domReady!"], function(dom){
    // This function does not execute until the DOM is ready
    dom.byId("someElement");
});

注意在回撥函式裡沒有定義引數來返回dojo/domReady的值。因為返回值沒有什麼作用,我們只是用它來延遲迴調。由於模組的本地變數名稱取決於模組之間的順序,不使用返回值的載入模組或外掛應放在require依賴關係列表的末尾。
即使沒有資料傳遞給外掛,感嘆號還是必須的。沒有它,你就只會將dojo/domReady模組作為一個依賴載入,而不是啟用它的特殊外掛功能。

小結

本教程提供的對AMD的基本理解將帶你入門Dojo開發,但你很快會發現自己陷入了更復雜的情況。閱讀Advanced AMD Usage 教程來了解更多:

  • 載入器和庫位於不同的位置甚至服務時如何配置載入器
  • 建立行動式模組的包
  • 載入同一模組或庫的多個版本
  • 載入非AMD程式碼

資源