天天看點

預覽ExtJS 4.0的新功能/新特性(一):渲染元件的方式

ExtJS 3.3的下一個版本就是4.0。——什麼!?您不知道?那就讓我們為你展開新一段的 Ext 之旅吧!

話說 ExtJS Roadmap(新版本線路圖)其中重要的一項就是“Rearchitected component rendering system - smaller, faster and simpler than ever before”,重新編制元件的渲染架構,目标是比以前更快、更精、更容易!。——舊 Ext 的渲染方式不好嗎?也不是,關鍵是沒有一個統一的建構元件機制。一般來說,建立一個自定義 Ext UI 元件,等于是各個元件的組合,例如一個 toolbar+grid 的配搭。如果需要建立特殊的控件,譬如一張圖檔加一個

checkbox,Ext 裡面就沒有這樣的元件,需要我們去定義一個、建立一個。于是我們就可以以 Ext.Component 為基類(superclass),通過Ext的繼承(Ext.extend),定義新的 img 和 checkbox 元件,當然還是以HTML标簽為基礎控制。我們所做的,首先是描述新控件它的結構,這種控件的結構可以稱作 DOM 結構,或簡單一點 HTML 結構。具體工作一般是先是聲明一個 div 或 autoEl,那往往都是 DOM Script(createElement()/appendElement()……)的方法,或者更“先進”的一種方式是按照“DomHelper”的結構寫

HTML 的 JSON 形式。定義結構的過程同時也是配置設定屬性的過程,例如這個 img 元素是幾高、幾寬都在裡面作說明。一般稱作是配置設定預設參數。還有就是預留資料接口的問題,比如 img 的 src 無法一早确定。再複雜的資料接口如何規劃,就上升到“資料綁定”的層面了,當定義好結構和參數等接口,就形成一個特定元件類供調用。執行個體化元件類時,就會将結構、參數的、外觀的樣式等等都注入到頁面 DOM 記憶體中(若“非延時加載”),成功的話就算完成了渲染。

盡管過去 Ext 還提出了元件生存周期的概念,可是它并不是一個建立元件的對象模型,較多的在回收事件句柄、修正元件記憶體洩漏時發揮的作用比較明顯。對于一般建構元件而言,需要與浏覽器原理更貼切、更直覺(Straightforward)的 API 來支撐。或者說,針對建立自定義元件時的流程轉向,提供一套圍繞元件“結構/資料”、“行為/事件”、“外觀/樣式”這三大理論高點而實作的邏輯程式。新内容可能會很精彩,但不用急于揭開神秘的面紗,沒有所謂的“神秘”,上面我們回憶一下過去是怎麼建立元件的,就是為了可以與4.0新方法對比一下。

是不是一定要了解 Ext 内部渲染才能寫元件?不見得,因為 Ex t就是立足要避開這些複雜性,我們了解怎麼有效率工作就足夠了。小弟這裡說多點嘛~隻是想學人家抛磚引玉,呵呵。閑話休提,下面立刻介紹4.0出現的三個新的配置項參數(config items),它們是 renderTpl:String/Ext.XTemplate、renderSelector:String 和 renderData:Object。

ExtJS4 新版所帶來的改進,其中之一是改變了渲染元件所依托的 div 結構。div 結構定義在Ext.Component.renderTpl(渲染模闆)中。該元件是什麼結構的,就會在 renderTpl 中反映出來。建立元件時,renderTpl 可以輸入字元串,其字元串會作為構造器的參數送入 Ext.XTemplate 形成模闆對象,進而借助該模闆對象的屬性和方法獲得對元件結構的控制能力。Ext 的模闆類是一個功能非常強大類,可支援子模闆、模闆表達式等的功能。此處的模闆就是勾勒整個元件的骨架脈絡。

打開源碼Component.js,renderTpl一項可是除了一個"div"什麼都沒有了。因為這是Component基類,具體内容需要特定的子類所決定,目前就是這個div而已了。但應當指出,哪怕是一個什麼内容都沒有的Ext.Component,也一定會有Ext.Component類所賦予它的預設屬性及其屬性值。首先分派一個獨一無二的id辨別,保證了各個元件之間不會命名沖突,否則擷取元件引用時會擷取不正确;其次是元件的基本類,即<div class="cls1 cls2 cls2" ……></div>。渲染過程必須配置設定好這些基本類,包括cls、cmpCls、baseCls和ui。

當自定義新Component時,可以覆寫原有的renderTpl:'div'配置項屬性,達到建立元件結構之目的。比如上一個“一張圖檔加一個checkbox的控件”的例子,就是:……

renderTpl:'<div><img src="afoo.jpg" mce_src="afoo.jpg" /><input type="checkbox" /></div>'

……

總之,可以預見的是,越複雜的元件伴随着越複雜的結構,是以必須謹記不時進行适當的優化。

這裡順便插一點。我們知道,Ext渲染的元件過程中生成大量的 HTML 标簽,成為元件的“骨架(skeleton)”。雖然都是通過腳本生成這些 divs,不需要逐個 div 去手寫,但是對性能而言畢竟隻會加重負荷。建立一個普通的面闆 Panel,底下起碼有4~6層的 div,每層 div 都有特定的功能。同時,大量 Markup 的出現也會增加調試的困難。使用者如果安裝有 firebug 調試工具,打開“HTML”觀察,就會看到一層層 div。曾經有資深 Widget 作者看到過如此複雜的HTML當場感歎Ext怎麼不節省一下。

剛才的renderTpl的内容是寫死的,僅作示範用,完整的一個Ext JS4.0元件建立方法如下:

IconComponent = Ext.extend(Ext.Component, {

iconCls: 'myIcon',

renderTpl: '<img alt="" src="{blank}" mce_src="{blank}" class="{iconCls}"/>',

initComponent: function() {

Ext.applyIf(this.renderData, {

blank: Ext.BLANK_IMAGE_URL,

iconCls: this.iconCls

});

Ext.applyIf(this.renderSelectors, {

iconEl: '.' + this.iconCls

IconComponent.superclass.initComponent.call(this);

},

changeIconCls: function(newIconCls) {

if (this.rendered) {

this.iconEl.replaceClass(this.iconCls, newIconCls);

}

this.iconCls = newIconCls;

有了 renderSelectors 不僅可以允許我們快捷地擷取元件對象,而且可以比較清晰地掌握關鍵的内部結構,排除一些不必要的 Tags。通過指定 renderSelectors 為具體的 class 屬性,任何一個元件的執行個體,都可以借助這個 renderSelectors 的尋址來找到。例如元件 body 的 renderSelectors 預設為 x-panel-body。

既然明确了結構,那麼接下來綁定内容實體應該是很容易的事情了。如果不要寫死結構的内容,我們可以通過讀寫 Ext.Component.renderData 配置項為元件提供資料内容。隻要在 Ext.Component.renderData 上加入了新的資料,都會視作為元件的内容資料,例如上例 {blank} 變為 Ext.BLANK_IMAGE_URL,iconCls變為'myIcon';隻要在 Ext.Component.renderSelectors 上定義了任何一個字段,都會視作 Ext.Element

類型的引用,是以上例中我們才可以使用“this.iconEl.replaceClass(this.iconCls, newIconCls);”替換樣式。

另外,如果要對 renderTpl 裡的某個 HTML 元素登記事件,利用 renderSelector 擷取目标 HTML 元素也是一個不錯的主意。

關于 this.renderSelectors.iconEl 怎麼變為 this.iconEl 的原理過程,原來也是很容易了解的。見 Component.js 第782行:

applyRenderSelectors: function() {

var selectors = this.renderSelectors || {},

el = this.el.dom,

selector;

for (selector in selectors) {

if (!selectors.hasOwnProperty(selector)) {

continue;

this[selector] = Ext.get(Ext.DomQuery.selectNode(selectors[selector], el));

新 ExtJS4釋出之後,大家看到源碼,那時應該會發現新的元件均會按照這種方式去定義的。采用新模式的元件是否真的會更利于元件的建立?4.0 尚在翹首期盼中,暫無結論,咱們拭目以待……

繼續閱讀