學習Dijit 的重要組成部分模板系統:Dijit._Templated ,以及如何使用模板來快速創建自己的小部件。
Dijit(Dojo的小部件庫)提供的_Widget 和_WidgetBase基類爲開發小部件提供了完整的基礎類,但是_Templated 基類的所引入的模板系統則使Dijit更顯強大和靈活。使用_Templated , 你可以快速的創建出易於維護,方便修改的小部件。 _Templated 的原理非常簡單:它允許開發者創建一小段HTML片段,片段在運行時會被作爲字符串加載(或者在build過程中直接內聯入代碼內)並被所有該小部件的實例所重用。接下來我們將會解讀_Templated提供了哪些功能,並且動手開發一個使用_Templated 的小部件。
注意:_Templated 應當被當作混入代碼使用(mixin), 而不是被直接繼承。用面向對象的觀點來看,_Templated 更接近一個接口而不是一個類(雖然在JavaScript中,並沒有辦法明確區分二者)
_Templated 提供了哪些方法和屬性
對使用_Templated 的程序員來說或,將_Templated 混入一個小部件將會給這個小部件的類帶來下列的新屬性:
templateString,//astring representing the HTML of the template
templatePath,//aURL pointing at a file to be used as a template
widgetsInTemplate//aBoolean indicating whether or not child widgets
//are defined in the template
注意:templatePath 現在已經基本不使用了,只是爲了向後兼容而保留。
下面的章節中我們會展示如何搭配使用dojo.cache 和 templateString .些新屬性看起來如此簡單,那麼多強大的功能僅憑這幾個屬性就能實現麼?真正的答案隱藏在_Templated向你的小部件定義中添加的其他內容。
_Templated覆寫的方法
除了上述幾個屬性之外, _Templated覆寫了Dijit Widget架構中的三個基礎法:buildRendering, destroyRendering, 和startup.這三個方法分別負責:解析並填充模板(buildRendering),正確銷燬Widget DOM樹(destroyRendering), 並保障模板中包含的子Widget能夠正確的被啓動(startup)
注意:因爲上述三個方法對於使用模板是必須的,如果你在自己的代碼中也進一步覆寫了這幾個方法,請務必在你的覆寫代碼中加入this.inherited(arguments)來調用父類的方法確保模板能正確處理。
使用_Templated
你只需要在創建Widget的類聲明中的第二個參數數組中加入“dijit._Templated",就可以讓你的Widget 支持模板. 例如,下面的代碼就聲明瞭一個支持模板的名爲SomeWidget的Widget
1. dojo.declare("example.SomeWidget",[ dijit._Widget, dijit._Templated ], {
2. templateString: dojo.cache("example","templates/SomeWidget.html")
3. // your custom code goes here
4. });
Dijit組件庫中的組件都遵循在當前Javascript目錄中創建一個單獨的名爲templates的目錄來保存模板的編碼習慣。我們建議你也遵循同樣的做法。
注意:在上述聲明中,我們搭配使用了dojo.cache 和templateString 屬性,dojo.cache方法會從其緩存或url中獲取資源。這是最新版dojo中推薦的用來獲取資源(例如這裏的模板文件)的做法,它確保了使用盡量少的HTTP請求來獲取資源.
現在我們已經有了可以支持模板的一個小部件的聲明,接下來我們要爲它寫一個模板,並且解釋模板可以包含哪些功能。
創建模板
一個模板就是一個HTML代碼片段,你可以在其中定義DOM結構,也可以注入一些特殊的內容。 我們先從一個簡單例子看起。
1. <divclass="${baseClass}" data-dojo-attach-point="focusNode"data-dojo-attach-event="ondijitclick:_onClick"role="menuitem" tabindex="-1">
2. <span data-dojo-attach-point="containerNode"></span>
3. </div>
在這個簡單的模板裏,演示了Dijit模板的3個重要功能:變量的替換,附着點(attach point), 以及DOM事件綁定. 接下來我們會依次解釋這三個功能。
注意:每個模板的HTML中只能有一個根節點。包含多個根節點的模板是非法的。
變量的替換:
模板中可以引用小部件中定義的變量的值。語法很簡單{property}
上述例子中,我們在模板的根節點的class屬性裏引用了變量baseClass的值(該變量適用於所有Widget). 如果該變量本身是一個對象的話,你還可以進一步引用該對象的屬性值。這時你需要在屬性名前加上一個!如:${!propertyObject.property}.
注意:從Dijit 1.5 開始,模板中使用變量值替換僅限用於哪些在小部件的整個生命週期中都不會變化的那些屬性。如果你希望可以在聲明週期中修改某屬性值,我們建議你在postCreate方法中通過調用set方法來設置。
附着點(Attache Points)
Dijit模板系統會在你定義的模板中尋找一個特殊的屬性(稱爲attach point) - 使用了HTML5 的數據屬性(data-*) 語法。一個連接點告訴模板渲染引擎: 如果模板中的某DOM節點上定義了data-dojo-attach-point 屬性,則該節點的引用會被設置爲在Widget中的對應屬性。例如, 在上面例子中的SomeWidget的模板定義了2個DOM節點。主節點(外層的div)可以在Widget代碼中被引用爲focusNode,而內層的span節點則可以通過Widget的containerNode屬性來引用。
注意: 通常即使你在模板中不設置任何attach point ,模板的根節點可以在widget中通過domNode來引用。所以大多數時候你用不着顯示的使用這個屬性。
containerNode 容器節點
Dijit定義了一個特殊的附着點叫做”containerNode". 從名字可以理解,containerNode就是一個容器節點,它爲使用聲明(declarative)方式創建的widget提供了放置額外標記片段的地方。例如:
1. <divdata-dojo-type="example.SomeWidget">
2. <p>This is arbitrary content!</p>
3. <p>More arbitrary content!</p>
4. </div>
這個片段使用聲明的方式創建了我們前面定義的SomeWidget的實例,在Dojo解釋器解析這個段落時,它會實例化一個SomeWidget,而實例化的同時在這裏被Div包含的HTML片段都會添加到SomeWidget所定義的容器節點中去。 所以當這個Widget被創建後,DOM樹的結構會是:
1. <divclass="someClass" role="menuitem"tabindex="-1">
2. <span>
3. <p>This is arbitrary content!</p>
4. <p>More arbitrary content!</p>
5. </span>
6. </div>
注意:上例中爲了教程的簡潔我們省去了一些自定義HTML5屬性。
類似的,如果你在Widget聲明中嵌入其他的Widget,那麼子Widget也將被添加到你的容器節點中去(前提是你的Widget定義了一個容器節點) . 例如:
1. <divdata-dojo-type="example.SomeWidget">
2. <p>This is arbitrary content!</p>
3. <div data-dojo-type="dijit.form.Button">MyButton</div>
4. <p>More arbitrary content!</p>
5. </div>
事件綁定
除了附着點,Dijit 模板系統還允許將原生DOM事件綁定到Widget的自定義方法上。這是通過另一個HTML5 自定義數據屬性完成的:data-dojo-attach-event 。 該屬性值是一組由逗號分割的鍵值對(鍵值間用冒號分開),鍵是原生DOM事件,值是要綁定此事件的Widget中的自定義方法。
例如:
1. data-dojo-attach-event="onmouseenter:_onHover,onmouseleave:_onUnhover,ondijitclick:_onClick"
這個例子裏我們定義的ondijitclick事件是一個Dijit自己定義的稍有改動onclick處理方法,在Dijit裏通常可以使用onclick 的地方都可以是用ondijitclick 代替。
當Widget被實例化時,Diji模板系統會自動遍歷所有的事件綁定屬性,並使用connect 將這些事件和Widget中的方法綁定起來。當DOM事件被觸發時,你的事件處理函數將能獲得跟原生DOM事件同樣多的參數,因此你可以完全的控制你的Widget.
widgetsInTemplate 屬性
最後,Dijit模板系統允許你使用widgetsInTemplate屬性來通過模板創建組合控件。顧名思義,widgetsInTemplate 指明瞭你的模板中是否包含其他的Widget(默認值爲false).
讓我們對我們前面的例子稍作修改,來讓它始終包含一個dijit.button
1. // 修改後的Widget定義
2. dojo.declare("example.SomeWidget",[ dijit._Widget, dijit._Templated ], {
3. templateString: dojo.cache("example","templates/SomeWidget.html"),
4. widgetsInTemplate: true
5. // 你的代碼
6. });
7.
8. // 模板定義
9. <divclass="${baseClass}" data-dojo-attach-point="focusNode"data-dojo-attach-event="ondijitclick:_onClick"role="menuitem" tabindex="-1">
10. <divdata-dojo-type="dijit.form.Button"data-dojo-attach-point="buttonWidget">My Button</div>
11. <spandata-dojo-attach-point="containerNode"></span>
12. </div>
請注意在修改後的模板中,我們在dijit.form.Button的div節點上定義了一個連接點buttonWidget. 此後我們可以直接使用myWidget.buttonWidget來直接引用這個內嵌的button的widget (而不是僅僅引用這個DOM節點). 使用這種方法,你可以使用一些簡單的widget來構建組合的widget,例如一個可以查看郵件列表的widget,或者是一個包含一系列按鈕的工具條控件。
注意:使用widgetsInTemplate 時可能會有額外的開銷,可能會影響你的widget的性能,甚至整個頁面的性能。如果你不是非常清楚的瞭解這個屬性的作用,最好還是將它設爲false.
結論
在這篇教程中,我們學習了Dijit 強大的模板系統,使用混入 _Templated,以及你如何使用模板來快速構建自定義的Widget
.我們還介紹瞭如何在模板中使用附着點,如何綁定DOM事件,以及如何構建包含其他widget的組合Widget的方法。