在應用中使用Ext Loader

  
  原文:http://www.sencha.com/blog/using-ext-loader-for-yo ur-application/
  ExtJS 4.0是一個使用新的依賴系統的類加載系統。這兩個強大的新功能允許你創建大量允許瀏覽器按需下載腳本代碼的應用。
  今天,我們將通過建立一個小的使用新的類加載系統的應用程序來熟悉一下依賴管理系統。同時,我們將討論Ext加載系統的各種配置項。
  在開始之前,我們先來看看將要實現的結果。這樣做,可使我們確定需要擴展那些類。
  
  應用會包括互相綁定的GridPanel和FormPanel,名稱分別爲UserGridPanel和UserFormPanel。UserGridPanel的操作需要創建一個模型和Store。UserGridPanel和UserFormPanel將被渲染到一個名稱爲UserEditorWindow的窗口,它擴張自ExtJS的Window類。所有這些類都會在命名空間MyApp下。
  在開始編碼前,首先要確定目錄結構,以下是使用命名空間組織的文件夾:
  
  從上圖可以看到,MyApp目錄已經按照命名空間進拆分成幾個目錄。在完成開發的時候,我們的應用將會有一個如下圖所示的內部依賴運行模型。 (儘管應用的目錄構成很象ExtJS 4 MVC架構,事實上示例並沒有使用它 )
  
  現在開始編寫index.html文件,這裏需要包含應用需要的啓動文件和應用的根文件(app.js)。 1 DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
  2
  3
  4 Ext 4 Loader
  5
  6
  7
  8
  9
  10
  11
  index.html文件中需要使用link標記包含ExtJS 4的樣式文件。包含ext-debug.js文件的javascript標記可能要修改多次,ext-all-debug.js文件是開發調試用的,而ext-all.js則是在發佈產品時使用的。
  這裏有幾個選擇,每個選擇都有優缺點。
  以下是這些文件的說明:
  ext-all-debug-w-comments.js:帶註釋的的完整調試版本。文件比較大,加載時間比較長。
  ext-all-debug.js : 不帶註釋的完整調試版本。文件也比較大,但很適合調試。
  ext-all.js ;壓縮後的完整版本,文件比較小。使用該版本調試很困難,因此一般在發佈產品時才使用。
  ext-debug.js : 該文件只包含ExtJS基礎架構和空的結構。使用該文件,可以實現ExtJS類文件的遠程加載,而且提供了很好的調試體驗,不過代價是相當的慢。
  ext.js : ext-debug.js的壓縮版本。
  我們的index.html將使用ext-debug.js文件,這是實現動態加載所需的最低要求。最後,我們將展示如何使用ext-all版本獲取最好的結果。
  由於UserGridPanel 類要求模型和Store,因而,要先定義編寫這些支持類。現在開始編寫模型和Store: 1 Ext.define('MyApp.models.UserModel', {
  2 extend : 'Ext.data.Model',
  3 fields : [
  4 'firstName',
  5 'lastName',
  6 'dob',
  7 'userName'
  8 ] 9 });
  以上代碼擴展自Ext.data.Model,將創建UserModel 類。因爲擴展自Ext.data.Model類,ExtJS會自動加載它,並在它加載後創建UserModel類。
  下一步,要創建擴展自Ext.data.Store的UserStore 類: 1 Ext.define('MyApp.stores.UserStore', {
  2 extend : 'Ext.data.Store',
  3 singleton : true,
  4 requires : ['MyApp.models.UserModel'],
  5 model : 'MyApp.models.UserModel',
  6 constructor : function() {
  7 this.callParent(arguments);
  8 this.loadData([
  9 {
  10 firstName : 'Louis',
  11 lastName : 'Dobbs',
  12 dob : '12/21/34',
  13 userName : 'ldobbs'
  14 },
  15 {
  16 firstName : 'Sam',
  17 lastName : 'Hart',
  18 dob : '03/23/54',
  19 userName : 'shart'
  20 },
  21 {
  22 firstName : 'Nancy',
  23 lastName : 'Garcia',
  24 dob : '01/18/24',
  25 userName : 'ngarcia'
  26 }
  27 ]);
  28 } 29 });
  當創建單件模式的UserStore 時,需要在UserStore原型添加一個requires關鍵字,它會在類實例化前,爲ExtJS提供一個類的請求列表。在這個示例,列表中只有UserModel 一個請求類。
  (實際上,在Store的原型中定義了model爲UserModel 類,ExtJS就會自動加載它。在requires關鍵字中列出的目的,是希望你的代碼能自文檔化(self-documenting),從而提醒你,UserModel 類是必須的 )
  好了,UserGridPanel視圖需要的基類已經創建了,現在可以創建UserGridPanel類了: 1 Ext.define('MyApp.views.UsersGridPanel', {
  2 extend : 'Ext.grid.Panel',
  3 alias : 'widget.UsersGridPanel',
  4 requires : ['MyApp.stores.UserStore'],
  5 initComponent : function() {
  6 this.store = MyApp.stores.UserStore;
  7 this.columns = this.buildColumns();
  8 this.callParent();
  9 },
  10 buildColumns : function() {
  11 return [
  12 {
  13 header : 'First Name',
  14 dataIndex : 'firstName',
  15 width : 70
  16 },
  17 {
  18 header : 'Last Name',
  19 dataIndex : 'lastName',
  20 width : 70
  21 },
  22 {
  23 header : 'DOB',
  24 dataIndex : 'dob',
  25 width : 70
  26 },
  27 {
  28 header : 'Login',
  29 dataIndex : 'userName',
  30 width : 70
  31 }
  32 ];
  33 } 34 });
  在上面代碼中,要注意requires 關鍵字,看它是怎麼增加UserStore 爲請求類的。剛纔,我們爲GridPanel擴展和Store擴展配置了一個直接的依賴關係。
  下一步,我們要創建FormPanel擴展: 1 Ext.define('MyApp.views.UserFormPanel', {
  2 extend : 'Ext.form.Panel',
  3 alias : 'widget.UserFormPanel',
  4 bodyStyle : 'padding: 10px; background-color: #DCE5F0;'
  5 + ' border-left: none;',
  6 defaultType : 'textfield',
  7 defaults : {
  8 anchor : '-10',
  9 labelWidth : 70
  10 },
  11 initComponent : function() {
  12 this.items = this.buildItems();
  13 this.callParent();
  14 },
  15 buildItems : function() {
  16 return [
  17 {
  18 fieldLabel : 'First Name',
  19 name : 'firstName'
  20 },
  21 {
  22 fieldLabel : 'Last Name',
  23 name : 'lastName'
  24 },
  25 {
  26 fieldLabel : 'DOB',
  27 name : 'dob'
  28 },
  29 {
  30 fieldLabel : 'User Name',
  31 name : 'userName'
  32 }
  33 ];
  34 } 35 });
  因爲UserForm 不需要從服務器端請求任何類,因而不需要添加requires定義。
  應用快完成了,現在需要創建UserEditorWindow類和運行應用的app.js。以下是UserEditorWindow類的代碼。因爲要將Grid和表單綁定在一起,因而類代碼有點長,請見諒: 1 Ext.define('MyApp.views.UserEditorWindow', {
  2 extend : 'Ext.Window',
  3 requires : ['MyApp.views.UsersGridPanel','MyApp.views.UserFormPanel'],
  4 height : 200,
  5 width : 550,
  6 border : false,
  7 layout : {
  8 type : 'hbox',
  9 align : 'stretch'
  10 },
  11 initComponent : function() {
  12 this.items = this.buildItems();
  13 this.buttons = this.buildButtons();
  14 this.callParent();
  15 this.on('afterrender', this.onAfterRenderLoadForm, this);
  16 },
  17 buildItems : function() {
  18 return [
  19 {
  20 xtype : 'UsersGridPanel',
  21 width : 280,
  22 itemId : 'userGrid',
  23 listeners : {
  24 scope : this,
  25 itemclick : this.onGridItemClick
  26 }
  27 },
  28 {
  29 xtype : 'UserFormPanel',
  30 itemId : 'userForm',
  31 flex : 1
  32 }
  33 ];
  34 },
  35 buildButtons : function() {
  36 return [
  37 {
  38 text : 'Save',
  39 scope : this,
  40 handler : this.onSaveBtn
  41 },
  42 {
  43 text : 'New',
  44 scope : this,
  45 handler : this.onNewBtn
  46 }
  47 ];
  48 },
  49 onGridItemClick : function(view, record) {
  50 var formPanel = this.getComponent('userForm');
  51 formPanel.loadRecord(record)
  52 },
  53 onSaveBtn : function() {
  54 var gridPanel = this.getComponent('userGrid'),
  55 gridStore = gridPanel.getStore(),
  56 formPanel = this.getComponent('userForm'),
  57 basicForm = formPanel.getForm(),
  58 currentRec = basicForm.getRecord(),
  59 formData = basicForm.getValues(),
  60 storeIndex = gridStore.indexOf(currentRec),
  61 key;
  62 //loop through the record and set values
  63 currentRec.beginEdit();
  64 for (key in formData) {
  65 currentRec.set(key, formData[key]);
  66 }
  67 currentRec.endEdit();
  68 currentRec.commit();
  69 // Add and select
  70 if (storeIndex == -1) {
  71 gridStore.add(currentRec);
  72 gridPanel.getSelectionModel().select(currentRec)
  73 }
  74 },
  75 onNewBtn : function() {
  76 var gridPanel = this.getComponent('userGrid'),
  77 formPanel = this.getComponent('userForm'),
  78 newModel = Ext.ModelManager.create({},
  79 'MyApp.models.UserModel');
  80 gridPanel.getSelectionModel().clearSelections();
  81 formPanel.getForm().loadRecord(newModel)
  82 },
  83 onAfterRenderLoadForm : function() {
  84 this.onNewBtn();
  85 } 86 });
  UserEditorWindow 的代碼包含了許多東西用來管理UserGridPanel和UserFormPanel類的整個綁定的聲明週期。爲了指示ExtJS在創建該類前加載這兩個類,必須在requires列表裏列出它們。
  現在完成最後一個文件app.js。爲了最大限度地提高我們的學習,將有3次修改要做。首先從最簡單配置開始,然後逐步添加。 首先,app.js會在ExtJS添加MyApp命名空間的路徑,這可通過調用Ext.loader.setPath方法實現,方法的第1個參數是命名空間,然後是加載文件與頁面的相對路徑。
  下一步,調用Ext.OnReady方法,傳遞一個包含Ext.create的匿名函數。Ext.create會在ExtJS 4.0初始化之後執行,以字符串形式傳遞的UserEditorWindow 類會被實例化。因爲不需要指向實例和希望立即顯示它,因而在後面串接了show方法的調用。
  如果你打開這個頁面(http://moduscreate.com/senchaarticles/01/pass1.htm l ),你會看到UI渲染,但很慢,並且ExtJS會在Firebug中顯示以下警告信息:
  
  ExtJS提示我們沒有使用加載系統最優化的方式。這是第二步要討論的問題。然後,這是一個好的學習機會,要好好理由。
  我們需要配置Firebug在控制檯中顯示XHR請求,以便在控制檯中看到所有請求,而不需要切換到網絡面板。這樣,我們不單可以觀察到類依賴系統的工作情況,還可以從所有ExtJS類加載的文件中通過過濾方式找到我們要求這樣的文件。
  在Firebug控制檯過濾輸入框中輸入"User",你會看到下圖所示的結果。
  
  從圖中可以看到,UserEditorWindow類第一個被加載,接着請求UserGridPanel。UserGridPanel 要求UserStore和UserModel類。最後加載UserFormPanel 類。
  我剛纔提到,ExtJS提示了我們沒有使用加載系統最優化的方式。這是因爲依賴是在Ext.OnReady觸發加載之後通過同步XHR請求確定的,而這不是有效的方式且難於調試。
  未來修正這個問題,可以修改app.js指示ExtJS先加載我們定義的類,這樣即可提供性能又便於調試: 爲了快速加載我們定義的類和避免調試信息,可簡單的在Ext.onReady前調用Ext.require,只是ExtJS請求UserEditorWindow類。這將會讓ExtJS在文檔HEAD標記內注入一個script標記,運行資源在Ext.OnReady前加載。
  查看http://moduscreate.com/senchaarticles/01/pass2.htm l 可看到它是如何工作地。在頁面加載後,你會注意到ExtJS沒有在控制檯顯示警告信息了。
  我們所做的是讓ExtJS框架和應用類延遲加載。雖然這樣做調試很好,但是對於需要快速調試的情況,頁面渲染時間會讓你感到痛苦。爲什麼?
  原因很簡單,因爲這需要加載許多資源文件。在示例中,ExtJS發送了193個Javascript資源請求到web服務器,還有部分是在緩存中的:
  
  我們創建了6個Javascript文件(5個類文件和app.js),這意味着加載要求的ExtJS文件有187個請求。當你在本地做開發的時候,這個方案可行,但不是最理想的和效果最好的。
  解決這個問題,我們可以使用折中方案,通過ext-all-debug加載ExtJS框架,動態加載我們的類文件。要實現這個,需要修改兩個文件。
  首先,需要修改Index.html,使用ext-all-debug.js替換ext.debug.js。 接着,修改app.js,開啓Ext.Loader: 1 (function() {
  2 Ext.Loader.setConfig({
  3 enabled : true,
  4 paths : {
  5 MyApp : 'js/MyApp'
  6 }
  7 }); 8
  9 Ext.require('MyApp.views.UserEditorWindow');
  10
  11 Ext.onReady(function() {
  12 Ext.create('MyApp.views.UserEditorWindow').show();
  13 });
  14 })();
  通過調用Loader.setConfig可開啓Ext.Loader,需要傳遞一個匿名對象,它的eanbled屬性設置爲true,而命名空間設置爲路徑映射。
  通過編輯app.js,在本地開發環境下,應用將會在1秒內完成加載和渲染。
  
  源代碼下載地址:http://moduscreate.com/senchaarticles/01/files.zip
  作者:
  Jay Garcia
  Author of Ext JS in Action and Sencha Touch in Action , Jay Garcia has been an evangelist of Sencha-based JavaScript frameworks since 2006. Jay is also Co-Founder and CTO of Modus Create , a digital agency focused on leveraging top talent to develop high quality Sencha-based applications. Modus Create is a Sencha Premier partner.
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章