深入理解_WidgetBase

來源:互聯網
上載者:User

通過本文您將學到Dijit包中的_WdgietBase模組是怎麼回事,以及它作為Dojo Toolkit中所有widget的基礎是如何工作的。

難度:中等Dojo版本:1.7原作者:Tom Trenka譯者:Oliver原文連結:http://dojotoolkit.org/documentation/tutorials/1.7/understanding_widgetbase/
簡介Dijit包的基礎架構,以及建立自訂widget的能力,在很大程度上依賴於一個定義在dijit/_WidgetBase模組的基類。雖然還有另一些常用的模組在開發基於Dojo的web應用時很有價值(例如Dojo parser和Dijit模板系統),但這個_WidgetBase是建立任何自訂widget時都要用到的。在本文中,您將學習到這個widget基礎設施是如何工作的。
注意:如果您具有早期Dojo版本的使用經驗,可能對dijit/_Widget模組比較熟悉。雖然目前dijit/_Widet仍然存在,並且繼承了dijit/_WidgetBase,但在撰寫您自己的widget時最好還是直接繼承djit/_WidgetBase。dijit/_Widget將很有可能從Dojo2.0中移除。
要理解Dijit系統,最重要的一點就是理解一個widget的生命週期。這個生命週期主要是關於widget的初始化過程。也就是說,從一個widget的建立,到完全可被您的應用所使用,再到銷毀該widget及其所涉及的DOM結點。
注意:Widget和WidgetBase之前之所以加上了底線"_",是因為它們不應該被直接執行個體化,而應通過dojo的declare機制來繼承。
_WidgetBase中的方法可分為兩條主線:一組在建立過程中順序調用的方法,以及一套在使用widget的過程中以最小的資料繫結來擷取/設定屬性的方法。現在讓我們來研究一下widget的建立過程。
Dijit生命週期任何一個以_WidgetBase為基類的widget在其初始化的過程中都會依次調用幾個特定的函數。下面以調用順序列出這些函數:
  • constructor (所有原型通用,初始化時被調用)
  • postscript (由declare聲明的所有原型通用)
  •      create
  •           postMixInProperties
  •           buildRendering
  •           postCreate
  • startup
查看樣本這些方法用於處理以下事情:
  • 何時定義初始值
  • 如何建立初始值的可視化表示
  • 這些可視化表示何時連入DOM樹
  • 何時執行依賴於連入DOM樹的DOM結點的代碼

postCreate()在建立自訂widget時,目前最需要記住的一個方法就是postCreate。當widget的所有屬性都已定義,且代表該widget的DOM結構已被建立(但在連入主DOM樹之前)時,這個方法被調用。這個方法之所以重要,是因為這是開發人員,也就是您,有機會在widget最終呈現給使用者之前做最後的調整的主要場所。這些調整包括設定任何自訂的屬性,等等。在開發一個自訂widget時,大多數(如果不是所有的話)的定製都會出現在這個函數中。
startup()可能Dijit生命週期中的第二重要函數就是startup了。這個方法在widget的DOM結構被連入主DOM樹之後被調用。在該函數之前,這個widget的所有子widget都已被建立並啟動了。這個函數對於複合widget(例如布局widget)是非常有用的。
注意:當使用編程方式初始化一個widget時,務必調用startup方法,且必須在將該widget放置到文檔DOM樹中以後再調用。建立好widget之後忘記調用startup方法是一個很常見的錯誤,讓您因為搞不懂為何widget不正常顯示而抓狂。
銷毀方法除了初始化方法之外,dijit/_WidgetBase還定義了一些銷毀方法(以調用順序列出):
  • destroyRecursive
  •      destroyDescendants
  •      destroy
  •           uninitialize
  •           destroyRendering
在建立您自己的widget時,任何必要的自訂銷毀行為都應該定義在destroy方法中(別忘了調用this.inherited(arguments))。Dijit內建的destroy方法已經能夠自動處理DOM結點和大多數對象,因此您大可不必從頭開始編寫這些邏輯。
注意:雖然destroy是銷毀widget的核心方法,但在顯式銷毀一個widget時最好調用destroyRecursive。這個方法能保證該widget的所有子widget也被銷毀。
DOM結點引用一個widget通常是某種使用者介面,因此大都具有某種DOM結構。_WidgetBase定義了一個表中屬性,叫做domNode,它是囊括整個widget的DOM結點的引用。如果您需要對widget的DOM樹做某些操作(例如將整個widget移動到DOM樹的另一個位置),您隨時可以擷取這個結點的引用。而且這個引用在postCreate被調用的時候就已經存在了。
除了domNode屬性之外,某些widget還定義了containerNode屬性。這是對widget的一個內部結點的引用,這個結點裡包含了一些HTML內容甚至是其他widget,它們往往是在您的widget聲明之外定義的,例如一個通過聲明方式建立的子widget。
注意:我們將在另一篇教程中討論containerNode屬性的重要性。目前只要知道這個屬性存在於某些widget中即可(尤其要注意它存在於所有繼承自dijit/_Container的widget)。
Getter和Setter除了關於初始化和銷毀的方法,_WidgetBase還預定義了許多所有widget都需要的屬性,以及一整套為屬性定義getter和setter的機制,這套機制通過標準的get和set方法起作用,這兩個方法在所有widget中都有定義。您可以在代碼中添加含有如下籤名模式的私人方法來利用這套機制:
// 您的widget的“foo”屬性: //  自訂getter_getFooAttr: function(){ /* do something and return a value */ }, //  自訂setter_setFooAttr: function(value){ /* do something to set a value */ }

一旦用這種方法聲明了這些方法對,您就可以通過_WidgetBase的標準的get和set方法來訪問您的自訂屬性了。例如在上面的例子中,您可以這麼寫:

//  假設widget執行個體名為myWidget: //  擷取"foo"屬性的值:var value = myWidget.get("foo"); //  設定"foo"屬性的值:myWidget.set("foo", someValue);
這個標準允許其他widget或控制邏輯能夠通過統一的方式與一個widget互動,並且在一個屬性被訪問時提供給您執行一些自訂邏輯的能力(例如對一個DOM片段的修改,等等),或者調用其他的方法(例如觸發一個事件或通知)。假設您的widget有一個自訂屬性value,您希望在value值被改變時通知其他人(可能通過您定義的一個onChange方法):
//  假設我們的屬性稱為"value": _setValueAttr: function(value){    this.onChange(this.value, value);    this._set("value", value);}, //  一個用於dojo/on的函數onChange: function(oldValue, newValue){ }

如您所見,這套機制使得定製getter和setter的行為變得非常方便。
注意:在撰寫您自己的widget時,對於任何需要特殊邏輯來實現自訂屬性的擷取和修改的情況,您都應該建立對應的getter和setter方法。而在使用您自己的widget時,也必須總是通過get()和set()方法來訪問屬性。只有這樣才能正確地調用自訂的getter和setter邏輯。另外,在建立自訂的setter方法時,您應當總是使用內部的_set方法來更新內部值,從而使dojo/Stateful的watch方法能正常工作。這個dojo/Stateful也是所有widget都繼承的基類。
監聽事件和主題最後,_WidgetBase為Dojo的兩個最重要的事件機制on()和subscribe()提供了封裝。這些方法主要是為了方便,其次是為了便於準確地初始化和銷毀widget。您不需要自己來定義這些方法,它們都是直接可用的。
使用.on()和.subscribe()都是很容易的:

//  assume we have a button widget called "btn",//  and we want the button to listen to the "bar" event on foo: btn.on(foo, "bar", function(){    //  注意"bar"在btn的上下文內執行!    this.set("something", somethingFromFoo);});
主題的訂閱(通過Dojo的pub/sub系統)也可用類似的方法實現。
在widget的基礎設施中定義on和subscribe的好處是,widget能夠跟蹤它的所有事件和主題訂閱,保證它們在widget被銷毀時被正確地取消綁定(或取消訂閱),從而避免記憶體泄露。
預定義的屬性和方法最後,_WidgetBase提供了一組預定義的屬性,以及對應的getter和setter(如果需要的話):
  • id: 用於標識該widget的唯一字串
  • lang: 一個很少用到的字串屬性,用於覆蓋預設的Dojo locale
  • dir: 有Bidi需求時很有用
  • class: widget的domNode的HTML class屬性
  • style: widget的domNode的HTML style屬性
  • title: 通常是指原生的工具提示HTML title屬性
  • baseClass: widget的根CSS class
  • srcNodeRef: 在widget被“控制項化”之前存在的DOM結點(如果有的話)。注意對於某些widget(例如模板widget)這個屬性將在postCreate後被重設,因為原有的結點已被丟棄了。

結論如您所見,Dijit的_WidgetBase基類為建立和使用widget提供了一個堅實的基礎,涵蓋了widget的所有方面(生命週期,DOM結點引用,getter和setter,預定義屬性和事件)。我們已經看到一個widget的postCreate()方法是開發自訂widget時最重要的生命週期方法,以及在編程執行個體化widget時調用startup()有多麼關鍵。我們還介紹了Dijit的getter/setter機制,以及一個widget的domNode屬性的重要性。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.