天天看點

ExtJS也玩依賴注射(DI)?

ExtJS 元件的 Xtype 大家都是了解的,就是為了友善元件的“延時渲染”而設的。類似地借助字元串辨別,我們可不可以應用 Store 的引用上呢?ExtJS 3.0 提供了這方面的支援,允許我們配置元件期間,不擷取真正的 Store 對象而告知元件正确的 Store 是哪一個。一探究竟,不禁要問是怎麼辦到的?的确,正如大家所料,還是像 Xtype 用字元串辨別對象那樣子就可以了。不過字元串乍聽來來,貌似不那麼專業和顯得非常普通。呵呵,感覺這東西不好說。幹脆換種叫法是,——什麼來的? 那個……“依賴注射(Dependency Injection)”。——大抵變相的說法即如此。

如上述,使用 Store 注射的場景應該是,目前的上下文沒有已建構完畢 Store 對象立刻組裝到對應的元件中。因為調用 Store 服務不屬于 Ext 元件的生存周期的一部分,有可能出現元件已渲染完畢,仍處于沒可用資料的狀态,此時可認為 UI 與資料源的通訊是異步的。如此一來,元件模型中就務必引入 Store  的辨別引用(Identifier of the store)。

Store 辨別在 API 定義中就是“storeId”,如下例所示:

orderStore = Ext.extend(Ext.data.JsonStore, {

storeId: "orderStore_1",

constructor: function() {

orderStore.superclass.constructor.call(this, {

fields : [ // Fields ]

});

}

storeId: "orderStore_1"配置好之後,就可以在元件中直接使用 id 引用對應的 Store。如下列的 orderGrid:

orderGrid = Ext.extend(Ext.grid.GridPanel, {

title: "訂單清單",

store: "orderStore_1",

width: 400,

height: 250,

initComponent: function() {

this.columns = [ // Columns ];

orderGrid.superclass.initComponent.call(this);

注意這裡的 store: "orderStore_1"其類型是字元串,Grid 元件才會去查詢 id 為 "orderStore_1"的Store對象。如果在舊版的 Ext 中不支援 Store 的依賴注射的話,輸入字元串的值就會報錯。

因為我們知道,Store 其 id 與 Store 本身的一一對應不能夠“隔空取物”,當中必定有聯系在一起的機制。那麼在 API 中這個類就是 Ext.StoreMgr,它是一個單例(Singleton)。其實 StoreMgr 的實作非常簡單,整個類代碼如下:

/**

* @class Ext.StoreMgr

* @extends Ext.util.MixedCollection

* store組管理器。這是全局的、并且是預設的。<br />

* The default global group of stores.

* @singleton

*/

Ext.StoreMgr = Ext.apply(new Ext.util.MixedCollection(), {

* @cfg {Object} listeners @hide

* 登記更多的Store對象到StoreMgr。一般情況下你不需要手動加入。任何透過{@link Ext.data.Store#storeId}初始化的Store都會自動登記。

* Registers one or more Stores with the StoreMgr. You do not normally need to register stores

* manually. Any store initialized with a {@link Ext.data.Store#storeId} will be auto-registered.

* @param {Ext.data.Store} store1 Store執行個體。A Store instance

* @param {Ext.data.Store} store2 (可選的)Store執行個體2。(optional)

* @param {Ext.data.Store} etc... (可選的)Store執行個體x……。(optional)

register : function(){

for(var i = 0, s; s = arguments[i]; i++){

this.add(s);

},

* 登出一個或多個Stores。

* Unregisters one or more Stores with the StoreMgr

* @param {String/Object} id1 Store的id或是Store對象The id of the Store, or a Store instance

* @param {String/Object} id2 (可選的)Store執行個體2。(optional)

* @param {String/Object} etc... (可選的)Store執行個體x……。(optional)

unregister : function(){

this.remove(this.lookup(s));

* 由id傳回一個已登記的Store。

* Gets a registered Store by id

* @param {String/Object} id Store的id或是Store對象。The id of the Store, or a Store instance

* @return {Ext.data.Store}

lookup : function(id){

return typeof id == "object" ? (id.events ? id : Ext.create(id, 'store')) : this.get(id);

// getKey implementation for MixedCollection

getKey : function(o){

return o.storeId || o.id;

Ext.StoreMgr 直接繼承于 Ext.util.MixedCollection,此 MixedCollection 乃 Ext 的專用集合類。本來小弟覺得,沒必要用上 MixedCollection,使用 JS 的 Array 豈不是更簡單?但由于 MixedCollection 封裝了更友善的排序、周遊、增加/删除等的功能,出于這方面的需求,使用 MixedCollection 的話又是合理的,Array 則太過簡單化。總之這是一個取舍的問題,若考慮用戶端優化為先的就應該隻用 Array 吧。值得一提的是,Ext.apply(new Ext.util.MixedCollection(),{……}); 不失為建立單例的一個靈活的用法。

p.s: 上述 Ext.StoreMgr 源碼引用的是ext3.0,3.3的 lookup() 方法可能更周全的考慮,請大家鑒别。

按照 register() 源碼注釋所說的,一般情況下你不需要手動加入 Store 到 StoreMgr,通過 Ext.data.Store.storeId 初始化的 Store 都會自動登記到 StoreMgr。當元件開始調用Store 的時候,就會執行 this.store = Ext.StoreMgr.lookup(this.storeId); 這樣的語句來查詢 Store,其中 this.storeId 就是 Store 的 id。

繼續閱讀