顯示具有 dojo 標籤的文章。 顯示所有文章
顯示具有 dojo 標籤的文章。 顯示所有文章

2015年10月30日 星期五

dojo Events

dojo Events

簡介

為了能應付各種不同的流覽器對事件物件(event object) 有不同的定義及不同的處理方式,dojo 對事件物件的定義及處理方式做了正規化 (normalized),確保在 dojo 中處理事件時,事件物件的屬性或處理方法不會因為流覽器不同,而有所不同。在 dojo 中,事件物件大致分為兩種: Event 及 MouseEvent。Event 物件由程式觸發,傳回物件的屬性較少,觸發型別 (type) 可以自定;自訂型別時,中、英文皆可使用,唯使用英文時,所有大寫字母 (Uppercase) 均會被轉換成小寫 (Lowercase);因此,自定型別時最好全部使用小寫字母,"_" 及 "-" 兩個符號也可以使用。所有的 MouseEvent 均由使用者經由圖形介面元件所觸發,觸發的型別有固定種類,傳回物件的屬性比 Event 物件多,多出來的屬性大多是具有游標相關的資訊。至於事件物件的屬性及可能的型別,可說是族繁不及備載;在 w3cschools 網頁中有詳細的列示及解釋。也可以在 JavaScript 中,當使用者觸發圖形介面元件的事件時,用 console.log(event); 指令,然後到主控台去查看完整的物件屬性。


dojo 正規化後常用之事件物件的屬性如下:

target:
觸發此事件的元素 (element)。
currentTarget:
目前的元素,指的是在事件上傳 (bubble up) 的階段,目前處理此事件的元素。
type:
觸發事件的型別。
layerX:
事件觸發時,相對於處理此事件的元素,游標所在的 X 軸座標。
layerY:
事件觸發時,相對於處理此事件的元素,游標所在的 Y 軸座標。
pageX
事件觸發時,相對於流覽器視窗,游標所在的 X 軸座標。
pageY
事件觸發時,相對於流覽器視窗,游標所在的 Y 軸座標。
relatedTarget:
在觸發 mouseover 及 mouseout 事件時,游標所在,或離開的元素。
charCode:
觸發按鍵事件時,按鍵的字母鍵值。
keyCode:
觸發按鍵時,按鍵的鍵盤碼(當觸發事件的按鍵並非一般字母鍵,例 Enter, esc 鍵)。

另有常用到的函式如下:

event.preventDefault():
停止事件預設設處理動作。
event.stopPropagation():
停止事件的上傳 (bubble up) 動作。
event.stopImmediatePropagation():
停止事件的上傳動作,同時停止觸發此元素的其它事件處理器 (handler)。
event.stop(event):
停止事件預設的處理動作,同時停止事件的上傳動作。

dojo 用來連接事件 (event) 及事件處理器 (event handler) 的模組元件為 dojo/on。繼承 dojo/evented 類別的物件則具有 on() 及 emit() 兩個函式。

2015年10月28日 星期三

dojo Creating Template Widget

dojo Creating Template Widget

簡介

dojo 除了提供一系列豐富的圖形介面的元件,也允許程師設計師自行建構圖形介面元件以符合應用的特殊需求。dijit/_WidgetBase 是所有圖形介面元件的基礎,所有的圖形介面元件都繼承自 dijit/_WidgetBase。要能夠在 dojo 中自行開發圖形介面元件,深入瞭解 dijit/_WidgetBase 是絕對必須的。

首先,dijit/_WidgetBase 預先定義了一些每個圖形介面元件都會繼承的共同屬性:

id:
用來辨識圖形介面元件的唯一名稱,型態為字串。可以自行指定或由 dijit 自行產生。
lang:
指定取代 dojo 預設使用的語言,這個屬性很少用到。
dir:
如果指定語言是從右至左,就用這個屬性來指定。
domNode:
圖形介面主要的 DOM 元素(Element),多數的圖形介面元件都會修改 HTML 的結構,這個屬性可以參考到組成圖形介面最終的 HTML 元素及節點。
class:
圖形介面元件 domNode 之 HTML 的 class 屬性。
style:
圖形介面元件 domNode 之 HTML 的 style 屬性。
title:
圖形介面元件 domNode 之 HTML 的 title 屬性。
baseClass:
圖形介面元件在 CSS 中的基本 class 屬性。
srcNodeRef:
圖形介面元件在 DOM 中的原始掛載點,某些圖形介面在建構時,這個掛載點會被重設或清除。

另外,dijit/_WidgetBase 定義了數個函式,藉以掌控整個圖形介面元件的生命週期,各函式名稱依執行先後次序列示如下:

  • constructor() // common to all prototypes, called when instantiated
  • postScript()
    • postMixInProperties()
    • buildRendering()
    • postCreate()
  • startup()

以下介紹各函式的作用:

constructor()
是所有類別都具備的函式,在實體化物件時,會被呼叫一次。
postScript()
會先呼叫 create() 函式,在 create() 函式中又會依次呼叫 postMixInProperties(), buildRendering(), 及 postCreate() 三個函式。
postMixInPorperties()
作用在將建立元件時所傳入的屬性參數或函式融入 (mixin) 到既有的屬性及函式中。
buildRendering()
作用在建構所有介面的 HTML 元素,並設定 domNode 的值,這個函式執行完畢時,圖形介面的 HTML 元素都己建構並設定完畢,但尚未將這些元素加入到 HTML 主文件中。
postCreate()
這個算是最重要的函式了,在所有的屬性都定義完畢,而且圖形介面相關的 HTML 段落都己建置完成,且加入 HTML 主文件之後,(將 HTML 段落加到 HTML 主文件的動作,在呼叫完 buildRendering() 和呼叫 postCreate() 兩函式之間完成),才會執行這個函式。但要注意的是,如果此元件有子元件時,子元件在此刻未必己經加到主元件中,因此,在此階段還不能進行元件最終尺寸的計算。
startup()
是第二重要的函式了,在圖形介面相關的 HTML 段落加入主文件後,同時所有的子圖形介面都己完成之後,這個函式才會執行。用程式法建立圖形介面元件時,最好在建立完畢後呼叫 startup() 函式,以確保所有的動作都完成。

另一個非常重要的工具是 dijit/_TamplatedMixin。有些複雜的圖形介面元件,其 HTML 段落非常的複雜,如果要靠 API 一步一步組成最終的 HTML 碼,實在是曠日費時,而且容易出錯。如果能直接寫成最終的 HTML 碼,直接掛載到預定的位置,那就容易多了。而 dijit/_TemplatedMixin 就職司此項工作;它可以讀取一個含有 HTML 段落的檔案,將其內容處理後掛載到 HTML 主文件上的指定掛載點,更進一步的還提供了參數取代的功能,可直接將屬性的定義以參數取代的方式代入 HTML 碼中。

在 HTML 的模版 (template) 中置入 ${propName} 字串,dijit/_TemplatedMixin 便會用名為 propName 的屬性值,來取代這個字串。

在模版中,還可以定義兩個屬性:

data-dojo-attach-point="nameNode"
會在 widget 中建立一個名為 nameNode 的屬性,其值可以直接參考到這個 DOM 元素。
data-dojoattach-event="onClick:handler"
用在將這個 DOM 元素連接到觸發的事件 (click),並呼叫事件的處理函式 handler()。

除此之外,dijit/_TemplaedMixin 還會為 widget 預設建立兩個屬性值:

domNode:
這個屬性值可以直接參考到 widget 中最主要的 DOM 元素。
containerNode:
如果這個 widget 有包含其它的子圖形介面元件,用這個屬性可以直接參考到子元件的 DOM 元素。

如果在 HTML 的模板 (template)中又包含了其它的 dijit,此時,必須另外 require 另一個名為 "dijit/_WidgetsInTemplateMixin" 的模組,同時,用到的 dijit 模組也必須 require 進來。 當使用用外部定義的 HTML 檔案時,要藉著 dojo/text 這個插件 (plug-in) 將檔案內容讀進來。

範例

範例中,自定一個圖形介面元件,元件的作用是計數器,每點一下元件,其中的數字便會加 1。這個範例設計的並不是很完善,主要的作用是在解釋如何建立一個自定的圖形介面而己。例如:如果不改變元件的大小,元件只能容納 2 位數。如果改變元件的大小,字形不會跟著變化,位置也不會保持在中間等等。

CSS

<style>
html{
     width:100%;
     height:100%;
}
body {
     margin:0 auto;
     width:1000px;
     height:100%;
     padding-top: 20px;
}
</style>

屬性都在 widget 中定義了,所以 CSS 中沒有什麼要寫的。

HTML

<body class="claro">

My Counter

</body>

HTML 中要設定一個掛載點,注意 data-dojo-type 屬性的值。

HTML

首先,先根據圖形介面所要求的外觀,建一個新檔,由網頁所在位置起始,檔案的相對路徑位置名為 "js/app/widgets/templates/MyCounter.html"。因為用 SyntaxHighlighter 在處理 ${baseClass} 時會變成 ${baseClass}="",所以這一段程式碼不用 SyntaxHighLighter 處理。內容如下:


<div ${baseClass}
    data-dojo-attach-point="buttonNode"
    data-dojo-attach-event="onClick:_increment">
    <div
        data-dojo-attach-point="counterNode"
        style="padding:10px 0px; font-size:48px; text-align:center}"></div>
</div>

在模版中,定義了兩個 data-dojo-attach-point,一個名為 "buttonNode",另一個名為 "counterNode",這樣在程式中比較好操作。此外,定義了一個 data-attach-event,在元件觸發點按事件時,呼叫 _increment() 處理函式。另有一個屬性變數 ${baseClass} ,但程式中並沒有針對 baseClass 屬性定值,所以並不會在最終的 HTML 裡,產生任何 class="someClasses" 的設定。


其次,建立一個新檔,由網頁所在位置起始,檔案的相對路徑為 "js/app/widgets/MyCounter.js"。

define([
    "dojo/_base/declare",
    "dijit/_WidgetBase",
    "dijit/_TemplatedMixin",
    "dojo/text!./templates/MyCounter.html",
    "dojo/dom-style"
    ],
function(
    declare,
    _WidgetBase,
    _TemplatedMixin,
    template,
    style
){
    return declare("MyCounter", [_WidgetBase, _TemplatedMixin], {
        // counter
        value: 0,
        baseClass:"",
        width:"64px",
        height:"64px",
        backgroundColor:"yellow",
        border:"10px solid blue",
        borderRadius:"10px",
        templateString:template,
        constructor: function(){
            this.inherited(arguments);
        },
        postscript:function(){
            this.inherited(arguments);
        },
        // minin with the parameters passed in
        postMixInProperties:function(){
            this.inherited(arguments);
        },    
        // create the DOM for this widget
        buildRendering: function(){
            this.inherited(arguments);
        },
        // setup the style of DOM node      
        postCreate: function(){
            var bNode = this.buttonNode;
            style.set(bNode, "width", this.width);
            style.set(bNode, "height", this.height);
            style.set(bNode, "background-color", this.backgroundColor);
            style.set(bNode, "border", this.border);
            style.set(bNode, "border-radius", this.borderRadius);
            style.set(bNode, "text-align","center"); 
            var cNode = this.counterNode;
            cNode.innerHTML = 0;
            this.inherited(arguments);
        },
        startup:function(){
         this.inherited(arguments);
        },
        // every time the user clicks the button, increment the counter
        _increment: function(){
            this.counterNode.innerHTML = ++this.value;
        },
        _getValuerAttr:function(){
            return this.value;
        },
        _setValueAttr:function(number){
            this.value = number;
            this.counterNode.innerHTML = this.value;
        }
    });
});

第 5 行用 dojo/text 從相對路徑為名為 "./templates/MyCounter.html" 檔案中讀入 HTML 段落的內容。 放在 template 變數中,然後在第 24 行將其設定成 templateString 屬性的值。
第 17~24 行設定各屬性值。
第 41~49 行設定 domNode 的各項外觀的屬性。
第 56~58 行定義事件處理器。
第 59~65 行定義兩個供外部使用的函式,一個用來讀取屬性 value 的值,有就是計數器的值,另一個用來設定。要注意的是這兩個函式的命名方式,都是 _get${PropName}Attr() 及 _set${PropName}Attr(),其中 ${PropName} 字串,用屬性的名稱來取代。

最後,則是主網頁中的內容。


建立好自定的 widget 之後,用法就和 dijit 中的圖形介面元件的用法一樣,唯一要注意的是元件的路徑名,必須正確。
第 18~25 行在主控台中印出各個和 DOM node 有關之屬性的值,記得到主控台去檢查印出值,必詳細思考一下。建立 widget 的步驟還算複雜,最好多多修改範例程式,並檢查結果,以充分瞭解其中的細節。

2015年10月24日 星期六

dojo AMD

dojo AMD

簡介

將應用程式模組化,這個觀念在軟體業界己經行之有年。程式經過詳細規劃並模組化後,比較容易撰寫、管理及維護。在 dojo 中,一個模組 (module) 在系統中就是一個檔案,每當使用 require() 要求載入一個模組時,載入器 (loader) 便會在檔案系統中尋找符合名稱的模組檔案,將其載入到 Javascript 的執行環境中,程式便會獲得一個參考值;並透過這個參考值讀取模組中的屬性值,或呼叫模組中的函式。只要知道在 dojo 中如何建立一個類別 (Class)之後,建立一個模組並非難事。

建立一個模組時,最重要的就是 define() 函式。其語法如下:

define(
  moduleId,
  // (optional; string)
  // an explicit module identifier naming the module being defined      
  dependencies,  
  // (optional; array of strings) 
  // list of module identifiers to load before calling factory
  factory 
  // (function or value) 
  // the value of the module, or a function that returns the value of the  
  // module
)
    moduleId
    指定模組的名稱,這個參數是選項,一般都不賦予值;從缺時,載入器 (loader) 便使用檔案名稱做為模組的名稱。模組若是用在定義一個類別時,檔案名稱開頭的第一個字母都會大寫,以符合物件導向程式語言的命名慣例,若是傳回一個物件,則檔案名稱的第一個字母則保持小寫。
    dependencies
    也是選項,不賦予值時,表示該模組完全獨立存在,與其它模組不相關。若模組的建立需依賴其它模組,也就是會使用到其它的模組時,要將所有相依的模組名稱放在陣列裡傳入。
    factory
    其實就是個函式;用來建立一個類別 (class) 或是物件 (object) 的函式,在物件導向的程式語言中有個特殊的名字,叫 factory。這個函式裡,便撰寫建立一個類別或物件的程式,這個函式一定要傳回一個參考值,否則其它模組或程式就沒有辦法使用這個模組了。

建立模組時,要先在檔案系統裡依照模組的分類及彼此間的關係建立目錄結構,以便將來載入及維護。

/* content in file js/app/Person.js */
define([
    "dojo/_base/declare"
    ],
function(
    declare
){
    var Person = declare(null, {
        constructor: function(name, age, residence){
            this.name = name;
            this.age = age;
            this.residence = residence;
            Person.count++;
        }
    });
    Person.count = 0;    // class variable
    return Person;
});

在 js/app/Person.js 這個檔案中,撰寫了一個名為 Person 的類別,因為要給予一個類別變數,所以先將類別指派給一個變數,定義完類別變數後,才將變數傳出去。這裡正好變數的名稱也取名為 Person,其實取什麼名字都可以。

第一個參數從缺,所以會用檔案的名稱做為模組的名稱。因為函式中用到了 dojo 的 declare() 函式,也就是這個模組和 "dojo/_base/declare" 這個模組有相依性,因此要相依模組的陣列中列出這個模組的名稱。隨後就是宣告類別,並傳回類別的參考值。

/* content in file js/app/Employee.js */
define([
    "dojo/_base/declare",
    "app/Person"
    ],
function(
    declare,
    Person
){
    return declare(Person, {
        constructor: function(name, age, residence, salary){
            this.salary = salary;
        },
        askForRaise:function(){
            return this.salary * 0.02;
        }
    });
});

在 js/app/Employee.js 中,則建立名為 Employee 的類別,因為 Employee 繼承了 Person,所以在相依模組的陣列中,也將 Person 模組列入。

/* content in file js/app/Boss.js */
define([
    "dojo/_base/declare",
    "app/Employee"
    ],
function(
    declare,
    Employee
){
    return declare(Employee, {
        askForRaise:function(){
            return this.inherited(arguments) * 2; // calling parent's method, also modify the method
        }
    });
});

在 js/app/Boss.js 中則建立名為 Boss 的類別,因為 Boss 繼承了 Employee,所以在相依模組的陣列中,也列入 Employee。雖然 Employee 和 Person 也有相依,但在此處無需列入 Person,載入器在載入 Employee 模組時,會自行依照 Employee 類別相依陣列的內容,加載 Person 模組。

在使用這些自定的模組時,要記得在 dojoConfig 中定義模組在檔案系統中放置的位置。




只要定義好自定模組在系統中的位置,在使用這些模組時,就和使用 dojo 的模組沒有什麼兩樣了。

dojo Creating Classes

dojo Creating Classes

簡介

雖說在 Javascript 用的是 prototyping 的繼承模式,並沒有其它物件導向程式語言中所謂「類別」(Class)的概念,在 Javascript 中只有「物件」(Object) 的存在,而且物件可以繼承另一個物件。但 dojo 在 Javascript 的基礎上還是實作了類似「類別」的概念。dojo/_base/declare 這個模組就是 dojo 中用來宣告一個類別的函式。在 dojo 中,物件可以多重繼承 (Multiple Inheritance)。在實務上,宣告類別時,多半會寫成模組,以單獨的檔案形式存在,但此篇只先討論在 dojo 中類別的宣告方式。

declare 的語法如下:

declare(classId, superClasses, mixin)

declare() 函式有三個參數,分別說明如下:

    classId
    為選項,可以不給,不給時該類別稱為「匿名類別」(Anonymous Class)。給予時,需給予包含命名空間(namesapce) 的類別名,整個名稱會是一個全域變數,格式為 "namespace/ClassId"。配合物件導向程式語言的一般命名規則,類別名稱的第一個字母會大寫。
    superClasses
    賦予值可以是 null 、一個類別名或是一個類別名陣列。賦予值為 null 時,表示此類別沒有任何要繼承的其它類別。賦於值為單一類別名時,表示此類別僅有一個父類別需要繼承。賦予值為一類別名陣列時,表示多重繼承,此類別會繼承陣列中所有的類別。此時要特別注意陣列中類別名在陣列中的前後次序,陣列中的第一個類別稱為基礎類別 (base class),由此類別依序將後繼類別的屬性和函式融入 (mixin),意味著當前類別和後繼類別具有相同屬性名或函式名時,後繼的屬性值和函式會取代先前類別的屬性值或函式。
    mixin
    最終的參數則是一個物件,此物件具有該物件特有的屬性及函式。同樣的,若繼承類別中的屬性名或函式名與此參數所提供的屬性名或函式相同時,則此參數中的屬性值和函式會取代繼承類別中的屬性值和函式。

mixin 中有個很特殊的函式叫 constructor(),這個函式就是物件的建構子。在每次用 new 這個操作子以建構一個新物件時,這個函式都會被呼叫一次。因此,這個函式通常都會將傳遞進來的參數,用來初始化 (initialize) 建構的物件。同時,這個函式會先行呼叫父類別的 constructor() 函式,並傳入參數,以初始化父類別的屬性;之後,再初始化本身的屬性。

另一個很特殊的函式是 this.inherited(arguments),用來呼叫父類別中的函式。語法如下:

inherited(methodId, arguments, [arg1, arg2,...]);
    methodId
    指定要呼叫父類別函式的名稱,如果從缺,則呼叫父類別中與呼叫 inherited() 函式相同名稱的函式,如果呼叫 inherited() 的函式沒有明確的函式名稱,例如「匿名函式」時,則須明確指定 methodId 的值。
    arguments
    Javascript 中的保留字,是一個含有全部傳入參數的陣列。
    [arg1, arg2,...]
    以此陣列成為呼叫父類別函式時的參數。從缺時,則傳入 arguments。


declare("Person",null, {
    name = "John"
});

var Person = declare(null, {
    name = "John"
});

以上兩種寫法都會產生一個名為 Person 的類別。

Script


第 9~15 行建構一個名為 "Person" 的類別。
第 17 行則建立一個類別變數 (class variable),計算由此類別所建構的物件數。
第 19~25 行建構一個名為 "Employee" 繼承 "Person" 的類別,加入 salary 屬性。
第 28~32 行建構一個名為 "Boss" 繼承 "Employee" 的類別,並修改 askForRaise() 函式,在函式中呼叫 "Employee" 的 askForRaise() 函式,取得傳回值後,再乘 2 。

2015年9月29日 星期二

dojo Create Dijit

dojo Create Dijit

簡介

dojo toolkit 為網頁應用的開發提供了一整組的使用者介面元件 (widget)。相對於大多數的開發工具稱它們的使用者介面元件為 widget,dojo 稱它自己的使用者介面元件為 dijit;因此,所有以 dijit 開頭的模組都是使用者介面元件。

使用 dojo 建立使用者介面元件的寫法有二種:

  • 宣告法 (Declarative)
  • 程式法 (Programmatic)

這兩種方法各有其優缺點,略述如下:

宣告法需經過 dojo 的剖析器 (dojo/parser) 對 HTML 做剖析以產生介面元件,執行速度上比較慢;而且在剖析的過程中,介面元件的外觀會先以流覽器預設的樣式顯示,然後再以被 dojo 「整容」後的外觀顯示。在這個過程中,畫面會有所謂「閃動」的情況,很多使用者不喜歡這種經驗。但宣告法在設計網頁時比較直覺,可以很迅速的產生網頁的雛型,以檢查網頁的佈置、介面元件的外觀及網頁的基本功能。

程式法則在程式中直接產生介面元件,隨後將元件掛載到 HTML 中的掛載點。優點是速度快,休沒有畫面「閃動」的情形;但設計網頁時,對元件的佈置不夠直覺,需要花較多的時間調整程式。

在實務上開發應用程式時,都會兩種方式混用;或分階段使用,也就是初期先以宣告法製作雛型,調整完頁面後,再以程式法改寫。有時也會視不同網頁的需求,各自採取不同的寫法。有些介面元件的的設計,在先天上就比較適合其中的某種寫法。像輸入表格就比較偏向使用宣告法製作。

以下的範例為利用 dojo 建立使用者介面的基礎方法,範例中共使用了二種宣告法和一種程式法。實際上,不論是宣告法或是程式法都有很多種的變異,也無法一一例舉。有了基本功後,就可以依需求自行變化了。

Script

<!DOCTYPE html>
<html lang="zh-Hant-TW">
<head>
dijit basic



</head>
<body class="claro">
</body>
    
    
    
    
    
    
</body>

</html>

第 7 行是 dojo 環境設定的一種簡式寫法,如果程式中沒有用到 dojo toolkit 以外的套件(package),或是用到自訂的模組,在為了瞭解介面元件的用法而寫一些簡單的測試網頁時,這樣寫比較省事;但真正寫應用系統時,這種簡式寫法通常是派不上用場的。
第 12 行到第 13 行是第一種宣告法,寫法和一般的 HTML 寫法差不多,只是在標記 (tag) 中多加了 data-dojo-type='dijit/form/Button' 的自訂屬性。告訴 dojo 的剖析器 (parser) 要取代這段 HTML 碼,在這裡放一個 dojo 的按鈕介面元件。這種寫法在流覽器 (browser) 無法下載 dojo 套件時,網頁的內容會以預設的樣式呈現;不過版面都亂了,也沒多大用處。但如果是要從 dojo 轉成使用其它的前端套件時,網頁的基本架構都在,有機會省點改寫的時間。
第 14 行到 19 行是第二種宣告法,這種方法就把宣告法用到極致。但是 HTML 碼和 dojo 的宣告及 Javascript 程式碼都混在一起,將來維護時就很費工夫了;要打的字又多,字打得多,出錯的機率就高;特別是雙引號、單引號混成一堆,也不容易看得清楚。夾在中間的 Javascript 函式也不能再利用,個人實在不認為是個好方法。
第 21 行算是給使用者介面的元件先定位,找個掛載點。
第 27 行指定定要下載 dijit/form/Button 模組,因為在後繼的 Javascript 程式碼中要用到。
第 32 行是 dijit/form/Button 傳給回呼函式時的參數名稱,如果是個類別 (Class) 模組,習慣上參數名稱的第一個字母會大寫。在 Javascript 程式中用這個名字來參考該模組。
第 37 行到第 43 行就是程式法的寫法了。
第 43 行呼叫 startup() 方法,讓 dijit 在網頁中成像 (rendering)。對於 Button 這種簡單的介面元件,有沒有呼叫 startup() 方法並不會造成任何差異,介面元件都會正常顯示,因為在模組中都會預設去呼叫 startup() 函式。但對於某些複雜的介面元件,特別是那種介面元件中又包含了其它的很多介面元件時,如果沒有呼叫 startup() 方法,在螢幕上可能就什麼都看不到,或是一團亂的情況。有時改了介面元件的一些屬性值時,也有可能需要重新呼叫 startup()方法,把介面元件再成像一次。所以,在介面元件建立後固定呼叫 startup(),算是個好習慣吧!

dojo Template

dojo Tamplate

環境

  • CSS3
  • HTML5
  • ECMA5 Javascript
  • dojo Toolkit 1.10
  • Chrome 43.0

基本模版

1 <!DOCTYPE html>
2 <html lang="zh-Hant-TW">
3 <head>
4 <title>dojo Configuration</title>
5 <meta charset="utf-8" />
6 <link rel="stylesheet" href="js/libs/dijit/themes/claro/claro.css">
7 <script>
8     dojoConfig={
9         async:true,
10         parseOnLoad:false,
11         baseUrl:"js/",
12         packages:[
13            {name:"dojo", location:"libs/dojo"},
14             {name:"dijit", location:"libs/dijit"},
15             {name:"dojox", location:"libs/dojox"},
16             {name:"utils", location:"app/utils"}
17         ]
18     }
19 </script>
20 <script src="https:js/libs/dojo/dojo.js"></script>
21 <head>
22 <body class="claro">
23 // Put HTML and dojo declarative code here
24 </body>
25 <script>
26 var app={};
27 require([
28     "dojo/parser",
29     "dojo/ready"
30     ],
31 function(
32     parser,
33     ready
34 ){
35     parser.parse();
36     ready(1, function(){
37     // 所有用到任何 dijit 的程式碼,都要放在這個函式裡面
38     // 否則在調用 dijit 時,很可能 dijit 當時尚未建立,因而得到 null 值
39     });
40 });
41 </script>
42 <html>

第 6 行載入所要使用的主題樣式,範例裡用的是 claro 主題樣式。
第 9 行的 async:true 設定使用 AMD (Asynchronous Module Definition) 模式。
第 11 行 baseUrl 的值是包含此段程式碼的 HTML 頁面到存放 dojo 套件的基本相對路。換句話說,baseUrl + location 即是 name 套件對 HTML 的完整相對路徑 。例如: dojo 這個套件的相對位置即為 js/libs/dojo ;而 utils 套件的相對路徑即是 js/app/utils。其餘套件的相對路徑,以此類推。
第 20 行的作用在載入最基本的 dojo 模組。
第 22 行指定 body 的 class 為 claro,用以套用主題樣式。這裡 class 的值一定要給,同時要和第 6 行中載入的主題樣式名稱一致。
第 26 行定義一個名為 app 的全域變數 (global variable),用來掛載未來程式中的變數及函式,在流覽器的主控台 (console) 中,可以用 window.app 這個變數名找到它。
第 27 到 30 行,使用 require() 函式,指定程式中所要使用到的 AMD 模組。parser 會在剖析 HTML 碼時,自行下載在 HTML 碼中宣告的 dijit AMD 模組; 因此,在 require() 函式中,就無須特別指定己宣告的 dijit 模組。
第 30 到 32 行,將至載的 AMD 模組以參數的方式,傳入回呼 (callback) 函式中。要注意的是參數的先後次序和 require() 下載 AMD 模組時所列示的先後次序,兩者必須一致。
第 34 行呼叫剖析器 (parser) 對 HTML 碼進行剖析 (parse),同時根據宣告進行 dijit 的建立。在 dojo 1.8 版後,剖析以非同步進行。因此,有用到在 HTML 碼中宣告建立之 dijit 的程式碼,都要放在 ready() 回呼函式中執行;否則,程式碼在執行時,用到的 dijit 可能還沒有建立完畢,因而造成錯誤。
第 35 行的 ready() 內回呼函式中所包含的程式碼,只會在 HTML 碼剖析完畢,而且所有的 djijt 都建立之後,才會執行。ready() 函式可以多次呼叫,第一個參數的數值決定呼叫的先後次序,數值愈小的愈早執行。