深入理解AMD模式下的Dijit
- 難度:初學者
- dojo 版本:1.8
- 作者:Mike Wilcox
- 譯者:Leslie (yurychika[at]gmail.com)
- 原文:http://www.sitepen.com/blog/2012/11/16/dive-into-dijit-with-amd/
Dojo Toolkit與其他JavaScript類庫最大的不同是Dojo的UI組件系統:Dijit。這是一個靈活的,綜合的Dojo 模組集合(由相對應的例片,CSS檔案等等補充)。Dijit能夠協助你建立靈活的,可擴充的,現代的組件。想要學習如何安裝,配置並且使用基本的Dijit在你的web應用中,請繼續閱讀。
引用合適的模組和資源
因為Dijit包括了一系列的UI組件,他綁定了4個支援的主題:nihilo, soria, tundra 和claro。每個主題包括了一系列的圖片和CSS檔案來控制組件的外觀。CSS檔案必須顯示地被包括在每一個HTML頁面中:
<style type="text/css"> /* dojo.css is a CSS Reset, and is optional. @import "http://ajax.googleapis.com/ajax/libs/dojo/1.8/dojo/resources/dojo.css"; /* Using the claro theme in this example */ @import "http://ajax.googleapis.com/ajax/libs/dojo/1.8/dijit/themes/claro/claro.css"; /* Note that if you don't specify a minor revision, e.g. 1.8.0 or 1.7.1, the CDN will deliver the latest version */</style>
在頁面中的body標籤中,或者在你的組件的父節點中,你需要根據你想要的主題定義class名。
<body class="claro">
你可以使用Dijit Theme Tester查看每一種主題。你也能夠定義自己的主題。
dojoConfig
在dojoConifg中有許多選項,但是最重要的兩個是async和isDebug。在開發過程中你會想要將isDebug設定成true一邊獲得適當的警告資訊。async選項用來告訴AMD Loader去使用全新的,快速的方法去載入JavaScript模組。
dojoConfig = { isDebug:true, async:true};
注意:parseOnLoad 是 dojoConfig 中的一個常用的選項,但是這個用法已經不再被推薦。請查看如下的關於 parser 的資訊。
dojoConfig是全域的並且必須在你載入Dojo之前被載入,不然它會被忽略。你也可以將configuration設定為script檔案上的一個屬性,這種情況下你將使用data-dojo-config。
<script src="http://ajax.googleapis.com/ajax/libs/dojo/1.8/dojo/dojo.js" data-dojo-config="isDebug:true, async:true" type="text/javascript"></script>
現在是時候來添加一個控制項。一個快速的測試是在頁面中添加一個按鍵,以便檢驗任何東西都如我們預料地進行。
<body class="claro"> <button data-dojo-type='dijit/form/Button'>Clicky</button></body>
dojo/parser
正如你看到的,控制項並沒有被正確地解析。我們需要載入dojo/parser 並且顯式地告訴dojo去解析這個控制項。我們何時做這件事?當讓是在當DOM準備好之後。AMD式判斷方法是使用dojo/domReady外掛程式。 AMD被告知一個被載入的依賴是一個擁有驚嘆號的外掛程式,比如:dojo/domReady!。因為我們不需要Dojo在解析之前做任何工作,我們可以安全地將這段代碼放在body的底部。
<body class="claro"> <button data-dojo-type='dijit/form/Button'>Clicky</button> <script> require([ 'dojo/parser', 'dojo/domReady!' ], function(parser){ parser.parse(); // tell dojo to check the DOM for widgets }); </script></body>
控制項在claro主題下被解析,但是在控制台有一個警告:WARNING: Modules being Auto-Required: dijit/form/Button.這條警告是因為控制項並未在任何地方被引入,為了是你的應用獲得最佳的效能,AMD與Dojo需要你顯式地定義你想在應用中使用的模組和依賴。Dojo1.8的解析器比較寬容。它非同步並且足夠聰明以至於能找到並且載入未被引入的模組。這是並不推薦使用的發放方法,因為這要比事先在你想要解析和渲染之前載入模組慢,但是它能夠捕獲錯誤並且在不阻塞應用的情況下告知我們還是很有用的。Dojo 1.7僅僅會失敗並且提示一條錯誤資訊。將dijit/form/Button加入require引用能夠解決這個問題並且提高效能。
Dijit系統的一個最顯著的特點是你可以使用一或兩種方法建立一個Dijit控制項:聲明式,使用HTML標記和自訂的屬性;或者編程式,使用純粹的JavaScript。讓我們看一看如何將一個基本select元素轉變成一個Dojo-enhanced控制項。
建立控制項
基本的select控制項
<select name="character" id="character"> <option value="">Select a character</option> <option value="Leonard">Dr. Leonard Leakey Hofstadter</option> <option value="Sheldon" selected="selected">Dr. Sheldon Lee Cooper</option> <option value="Rajesh">Dr. Rajesh Ramayan Koothrappali</option> <option value="Howard">Howard Joel Wolowitz</option></select>
這是一個靜態包含了一系列options元素的select元素。我們知道我們想要將這個select元素變成一個dijit/form/FilterSelect控制項,因此我們必須require這個模組。
require([ 'dojo/parser', 'dojo/domReady!', 'dijit/form/FilteringSelect'], function(parser, domReady, FilteringSelect){ parser.parse();});
既然dijit/form/FilterSelect模組已經可用,並且parser正在尋找DOM中的控制項,我們可以使用聲明式或者編程式的方法來enhance我們的select元素。
聲明方式
聲明式的增強select元素的方法是在HTML元素本身完成的。
<select name="character" id="characterNode" data-dojo-type="dijit.form.FilteringSelect" data-dojo-props='autoComplete:true, pageSize:10' > <option value="">Select a character</option> <option value="Leonard">Dr. Leonard Leakey Hofstadter</option> <option value="Sheldon" selected="selected">Dr. Sheldon Lee Cooper</option> <option value="Rajesh">Dr. Rajesh Ramayan Koothrappali</option> <option value="Howard">Howard Joel Wolowitz</option></select>
這個聲明式的例子闡述了data-dojo-type的使用以便標識出哪個Dijit應該被使用在給定的元素之上。當我們調用parser.parse()時, Dojo將會發現這個元素並且執行個體化並初始化控制項。
dijit/form/FilteringSelect模組的選項也是自訂屬性。當使用者輸入一個值之後控制項會自動填入並且每一頁顯示10項。就像一個普通的select元素那樣,“sheldon”會在初始被選中。
編程式
增強select元素的編程方法是完全使用Javascript完成的。
require([ 'dojo/domReady!', 'dijit/form/FilteringSelect'], function(domReady, FilteringSelect){ var filteringSelect = new FilteringSelect({ autoComplete: true, pageSize: 10 },'characterNode'); });
注意dojo/parser被從依賴列表中移除了,因為編程式初始化控制項不需要載入dojo/parser模組。我們可以用相同方法建立另外一個控制項。
require([ 'dojo/domReady!', 'dijit/form/FilteringSelect', 'dijit/form/Textbox', 'dijit/form/Textarea', 'dijit/form/Checkbox', 'dijit/form/RadioButton',], function(domReady, FilteringSelect, Textbox, Textarea, RadioButton){ var filteringSelect = new FilteringSelect({ autoComplete: true, pageSize: 10 },'characterNode'); var input = new Textbox({/*options*/},'myInputNode'); var textarea = new Textarea({/*options*/},'myTextareaNode'); var mySelect = new FilteringSelect({/*options*/},'mySelectNode'); var date = new DateTextBox({/*options*/},'myDateNode'); var time = new TimeTextBox({/*options*/},'myTimeNode'); var checkbox = new CheckBox({/*options*/},'myCheckboxNode'); var radio1 = new RadioButton({/*options*/},'myRadio1Node'); var radio2 = new RadioButton({/*options*/},'myRadio2Node');});
如果你有一個龐大的form並且不想將所有的單獨元素加入dijit控制項中,你可以建立自己的迷你parser以便通過選取器來建立Dijits.
require([ 'dojo/domReady!', 'dojo/query', 'dijit/form/FilteringSelect', 'dijit/form/Button', 'dijit/form/CheckBox', 'dijit/form/RadioButton'], function(domReady, query, FilteringSelect, Button, CheckBox, RadioButton){ query('button,select,input').forEach(function(node){ var type = node.nodeName; if(type === 'INPUT'){ type = node.type.toUpperCase(); } switch(type){ case 'BUTTON': new Button({},node); break; case 'SELECT': new FilteringSelect({},node); break; case 'RADIO': new RadioButton({},node); break; case 'CHECKBOX': new CheckBox({},node); break; } });});
當然,這個簡單的例子並不是把node屬性轉換成變數並且將其提供給控制項,也不是dojo/parser的任何特殊功能。
訪問dijit屬性
訪問某一個特定的DOM元素可以簡單地用dojo/dom.byId方法完成。Dijit有他自己的dijit/registry.byId方法來擷取註冊了ID的Dijit控制項。如果dijit控制項擁有一個ID,控制項ID 將會是同一個值。如果元素沒有一個ID屬性,一個控制項ID將會被自動產生。如果我們想要擷取上面用聲明方式建立的“characterNode” Dijit控制項,我們可以使用如下的代碼:
require([ 'dojo/domReady!', 'dojo/parser', 'dijit/registry', 'dijit/form/FilteringSelect'], function(domReady, parser, registry, FilteringSelect){ parser.parse(); var filteringSelect = registry.byId('characterNode'); console.log('filteringSelect', filteringSelect);});
在firebug內使用registry.byId查看Dijit的所有方法和屬性。
如果我們想要訪問pageSize屬性,我們可以用Dijit getter來訪問:
var pageSize = registry.byId('characterNode').get('pageSize'); // returns 10
如果我們想要改變pageSize的值,可以使用如下代碼:
registry.byId('characterNode').set('pageSize',20); //now pageSize is 20
注意:Dojo 1.5引入了“get”和“set”方法來處理屬性。在Dojo 1.4或者更早,你可以在前面例子中的使用get和set的地方使用“attr”。
監聽控制項事件
Dijit控制項使用dojo/on方法來監聽給定控制項上的DOM事件:
filteringSelect.on('change', function(value){ console.log('value', value);});
每個控制項都支援一系列的事件所以請仔細查看文檔以卻確定你想要監聽的事件是被支援的。
注意到它們是DOM事件是很重要的。如果你想要監聽widget方法,你應該使用dojo/aspect:
require([ 'dojo/aspect' // other deps...], function(aspect){ aspect.after(filteringSelect, 'validate', function(value){ console.log('validate', value); });});Dijit系列
Dijit也是一個傑出的UI庫,它有潛力來增強你的網站並且節約你很多的時間。Dijit包括許多控制項,包括:
- 上下文,彈出,下拉式功能表
- 表單元素比如按鍵,勾選框,單選框和文字框
- 日期和時間選擇控制項
- WYSIWYG編輯器
- 水平和垂直滑動條
- 進度條
- tab和Accordions
- 樹狀結構(包括拖拽)
- 對話方塊和提示
- 布局控制項
並且如果Dijit沒有您需要的控制項,很有可能在DojoX(Dojo Extensions)中有!如果想看上面提到的各種控制項,請訪問Dojo Theme Tester.