作者: Tom Trenka
原文連結: http://dojotoolkit.org/documentation/tutorials/1.6/understanding_widget/
譯者: feijia (tiimfei@gmail.com)
本教程中,你將會學到Dijit中的_Widget和_WidgetBase這兩個重要的基類對象,理解它們作為所有Dojo小組件的基類的作用和功能。
難度:中等
適用Dojo版本: 1.6
建立Dijit (dojo的小組件庫) 和自訂小組件的基礎,是由兩個基類構成的: dijit._widgetBase和 dijit._Widget. 當然Dijit系統還包含其他一些重要的工具例如Dojo的解析器,和Dijit模板系統. 在這個教程裡,你將會學到Dijit的基礎架構是如何運作的。理解了這些,使用和建立Dijit會變的更加容易。
注意:dijit._Widget 繼承自 dijit._WidgetBase; 如果你需要建立自訂的小組件,那麼你應當繼承 dijit._Widget 而不是dijit._WidgetBase, (當然你也可以直接繼承其他Dijit中現有的小組件)
也許你已經注意到了,這兩個基類前面都有一個底線“_" ,這實際上是Dojo中對內部類的一種命名規範。表示這個類不應被使用者直接使用,而是作為基類被繼承的。
學習Dijit 庫,最關鍵的是要能理解每個小組件的生命週期:從這個小組件被建立,到它能被程式使用,再到最終它被銷毀(生命週期也包含了建立與銷毀這個小組件所對應的頁面中的DOM元素)
Dijit的生命週期
每個繼承自dijit._Widget的小組件在執行個體化時都會經曆下面的方法調用過程:
([widget].constructor());
[widget].postscript();
[widget].create();
[widget].postMixinProperties();
[widget].buildRendering();
[widget].postCreate(); // 這個方法對開發人員而言是最重要的
[widget].startup();
查看樣本
從這些方法的名字我們大概可以猜測出它們的作用:
1. 何時初始化參數
2. 建立對應這些參數的圖形,DOM元素
3. 確定放置這些元素的位置,
4. 如何處理瀏覽器相關的一些問題(例如 DOM node measurements)
[widget].postCreate()
對於小組件的開發人員來說,postCreate()可能是最重要的一個方法了。
這個方法會在小組件的所有屬性參數設定好,小組件所使用的DOM樹節點被建立完成後調用。而此時該小組件的DOM節點還沒有被添加到主文件中去。因此這個方法是在小組件被呈現給終端使用者之前,開發人員可以做最多定製的地方。(例如設定許多自訂參數和屬性). 這就好像是一齣戲的大幕拉開之前,你可以做的最後準備工作的環節. 在開發自訂小組件時,絕大多數定製的屬性和行為都會在這裡被加入.
[widget].startup()
在Dijit一系列生命週期中,另一個重要方法是啟動方法startup. 這個方法會在DOM節點被建立並添加到網頁之後執行,同時在這個方法也會等待當前小組件中所包含的子控制項被建立並正確啟動之後才執行。
注意: 當你用編程的方法建立一個小組件時,記得一定要調用它的startup()方法。很多開發人員常犯的錯誤就是僅僅建立了小組件對象卻忘記調用startup(),結果就會導致小組件在頁面上無法正確顯示。
析構和銷毀方法
除了建立和啟動,dijit._WidgetBase 還定義了一系列用於析構和銷毀的方法:
[widget].destroy();
[widget].destroyDescendants();
[widget].destroyRecursive();
[widget].destroyRendering();
[widget].uninitialize();
在開發自訂小組件時,你需要覆寫[widget].uninitialize 方法,在其中釋放你所使用的資源. Dijit架構會自動的負責銷毀該Widget所使用的DOM節點,以及大部分的對象.
引用小組件的DOM節點
通常來說, Dijit小組件都是一些介面元素,因此多數會包含一些DOM節點。 Dijit._WidgetBase中定義了一個屬性domNode ,該屬性會指向該小組件中所使用的DOM根節點. 當該小組件的postCreate方法執行後,domNode屬性就可以使用了。通過使用這個屬性,你可以擷取並操縱根節點,例如你可以把這個小組件整體移動到DOM樹中的另一個位置上。
除了domNode屬性外,有些小組件還會定義一個containerNode屬性. 這個屬性指定了小組件DOM中的一個容器節點,用來包含子控制項。(參看另一篇Dijit模板教程)
Getters和Setters
_WidgetBase 作為基類,除了提供了一些通用的標準屬性,它還定義了一套標準的getter和setter方法來訪問開發人員自訂屬性。這套標準要求你定義一些私人方法(JavaScript中並沒有真正的私人方法,Dojo遵循的一種編碼規範是使用底線開頭的方法名表示類的私人方法)
// 例如你的小組件中需要對外暴露一個"foo"屬性, 則需要定義下列兩個私人方法 // custom getter_getFooAttr: function(){ /* do something */ }, // custom setter_setFooAttr: function(value){ /* do something */ }
一旦你定義了上述兩個方法,使用者就可以使用dijit架構的標準get和set方法來訪問你的自訂屬性. 例如在定義了上述兩個私人方法後,現在使用者可以直接使用get和set來訪問foo屬性。
// 假設這個小組件的執行個體是"myWidget" // get the value of "foo":var value = myWidget.get("foo"); // set the value of "foo":myWidget.set("foo", someValue);
通過定義Dijit標準的getter和setter方法,不僅規範了編碼風格,更重要的是它增加了靈活性。你可以在這些getter和setter方法中加入自訂的其他動作,例如當一個屬性被訪問時,你可以對DOM節點做相應的修改,或者是發出某些事件的通知資訊. 看下面的例子:
// 假設我們需要在Value屬性發生變化時觸發onChange _setValueAttr: function(value){ this.onChange(this.value, value); //注意這裡使用了Dijit標準的_set方法 this._set("value", value);}, // a function designed to work with dojo.connectonChange: function(oldValue, newValue){ }
注意: 在開發小組件時,請務必使用上述的標準getter和setter方法來訪問存取自訂屬性。另外在實現私人的setter方法時,也務必要使用_set方法。 這是因為通過使用該方法Dijit控制項就可以使用Dojo.Stateful中的watch方法。
在Dijit中使用事件和訊息訂閱
_WidgetBase還定義了connect和subscribe方法。它們也遵循Dojo中通用的事件和訊息訂閱機制。因此所有的Dijit小組件都自動了擁有了對事件處理能力:
// 假設我們有一個dijit.Button小組件btn// 我們希望這個button能夠監聽foo.bar(): btn.connect(foo, "bar", function(){ // 注意這個回呼函數的執行內容是在btn對象中! this.set("something", somethingFromFoo);});
Dijit的主題訊息訂閱也是類似的。
通過在_WidgetBase中定義connect和subscribe方法,所有的Dijit小組件都有了事件處理功能;另外通過_WidgetBase中定義的connect和subscribe方法,所有的訂閱和串連都會被自動記錄,因此在小組件銷毀時也可以自動的釋放和退訂相應事件,從而避免了潛在的記憶體泄露問題。
Dijit預定義的屬性和事件
最後我們來看看_Widget 預定義了哪些屬性。
id, // 唯一標記該小組件執行個體的標識符lang, // 該小組件所使用的語言標記,可以覆蓋Dojo全域的語言設定。dir, // 雙向語言支援的標記(值可以為rtl或者ltr)用來支援阿拉伯語等從右向左顯示的語言class, // domNode(小組件根節點)的HTML class屬性style, // domNode(小組件根節點)的HTML style 屬性title, // HTML title 屬性tooltip, // 可選的指向 dijit.Tooltip 的引用baseClass, // 小組件的根層級的css類名srcNodeRef // 在被轉換為小組件前的原始DOM節點
然後我們也一起瞭解一下哪些事件是dijit所支援的,(你可以串連到這些事件,也可以覆寫這些事件)
// 滑鼠事件onClick,onDblClick,onMouseMove,onMouseDown,onMouseOut,onMouseOver,onMouseLeave,onMouseEnter,onMouseUp, // 鍵盤事件onKeyDown,onKeyPress,onKeyUp, // 其他事件onFocus,onBlur,onShow,onHide,onClose
總結
本文介紹了Dijit的 _widget 和_WidgetBase 中所提供了基礎架構方法和屬性,這些共同構成了Dijit架構: 生命週期,DOM'節點引用,自訂屬性存取方法getter和setter以及預定義的屬性和事件. 有了這些堅實的基礎架構,開發一個自己的Dijit小組件也變得很簡單。
參考
建立一個自訂小組件
建立基於模板的小組件
dijit._Widget 文檔(dojo參考手冊 )