在EXTJS官網(wǎng)看到一片文章,講的是Extjs.Loader的使用方法,文章非常詳細(xì)的介紹了 Loader的機(jī)制及用法,感覺(jué)非常不錯(cuò),但無(wú)奈英文實(shí)在太爛,就沒(méi)轉(zhuǎn)過(guò)來(lái)。昨天恰好在CSDN看到了這篇文章的譯文,而譯文的質(zhì)量非常高,對(duì)譯者的翻譯 水平怎一個(gè)羨慕了得。廢話不多說(shuō),正文開始。
在開始之前,將英文原文鏈接放上來(lái),英文水平高的可以看看原文哦。
鏈接地址:www.sencha.com/blog/using-ext-loader-for-your-application/
ExtJS 4.0是一個(gè)使用新的依賴系統(tǒng)的類加載系統(tǒng)。這兩個(gè)強(qiáng)大的新功能允許你創(chuàng)建大量允許瀏覽器按需下載腳本代碼的應(yīng)用。
今天,我們將通過(guò)建立一個(gè)小的使用新的類加載系統(tǒng)的應(yīng)用程序來(lái)熟悉一下依賴管理系統(tǒng)。同時(shí),我們將討論Ext加載系統(tǒng)的各種配置項(xiàng)。
在開始之前,我們先來(lái)看看將要實(shí)現(xiàn)的結(jié)果。這樣做,可使我們確定需要擴(kuò)展那些類。

應(yīng)用會(huì)包括互相綁定的GridPanel和FormPanel,名稱分別為UserGridPanel和UserFormPanel。 UserGridPanel的操作需要?jiǎng)?chuàng)建一個(gè)模型和Store。UserGridPanel和UserFormPanel將被渲染到一個(gè)名稱為 UserEditorWindow的窗口,它擴(kuò)張自ExtJS的Window類。所有這些類都會(huì)在命名空間MyApp下。
在開始編碼前,首先要確定目錄結(jié)構(gòu),以下是使用命名空間組織的文件夾:

從上圖可以看到,MyApp目錄已經(jīng)按照命名空間進(jìn)拆分成幾個(gè)目錄。在完成開發(fā)的時(shí)候,我們的應(yīng)用將會(huì)有一個(gè)如下圖所示的內(nèi)部依賴運(yùn)行模型。
(盡管應(yīng)用的目錄構(gòu)成很象ExtJS 4 MVC架構(gòu),事實(shí)上示例并沒(méi)有使用它 )

現(xiàn)在開始編寫index.html文件,這里需要包含應(yīng)用需要的啟動(dòng)文件和應(yīng)用的根文件(app.js)。
- <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
- <html>
- <head>
- <title>Ext 4 Loader</title>
- <link rel="stylesheet" type="text/css" href="js/ext-4.0.1/resources/css/ext-all.css" />
- <script type="text/javascript" src="js/ext-4.0.1/ext-debug.js"></script>
- <script type="text/javascript" src="js/MyApp/app.js"></script>
- </head>
- <body>
- </body>
- </html>
index.html文件中需要使用link標(biāo)記包含ExtJS 4的樣式文件。包含ext-debug.js文件的javascript標(biāo)記可能要修改多次,ext-all-debug.js文件是開發(fā)調(diào)試用的,而ext-all.js則是在發(fā)布產(chǎn)品時(shí)使用的。
這里有幾個(gè)選擇,每個(gè)選擇都有優(yōu)缺點(diǎn)。
以下是這些文件的說(shuō)明:
ext-all-debug-w-comments.js:帶注釋的的完整調(diào)試版本。文件比較大,加載時(shí)間比較長(zhǎng)。
ext-all-debug.js : 不帶注釋的完整調(diào)試版本。文件也比較大,但很適合調(diào)試。
ext-all.js ;壓縮后的完整版本,文件比較小。使用該版本調(diào)試很困難,因此一般在發(fā)布產(chǎn)品時(shí)才使用。
ext-debug.js : 該文件只包含ExtJS基礎(chǔ)架構(gòu)和空的結(jié)構(gòu)。使用該文件,可以實(shí)現(xiàn)ExtJS類文件的遠(yuǎn)程加載,而且提供了很好的調(diào)試體驗(yàn),不過(guò)代價(jià)是相當(dāng)?shù)穆?/p>
ext.js : ext-debug.js的壓縮版本。
我們的index.html將使用ext-debug.js文件,這是實(shí)現(xiàn)動(dòng)態(tài)加載所需的最低要求。最后,我們將展示如何使用ext-all版本獲取最好的結(jié)果。
由于UserGridPanel 類要求模型和Store,因而,要先定義編寫這些支持類。現(xiàn)在開始編寫模型和Store:
- Ext.define('MyApp.models.UserModel', {
- extend : 'Ext.data.Model',
- fields : [
- 'firstName',
- 'lastName',
- 'dob',
- 'userName'
- ]
- });
以上代碼擴(kuò)展自Ext.data.Model,將創(chuàng)建UserModel 類。因?yàn)閿U(kuò)展自Ext.data.Model類,ExtJS會(huì)自動(dòng)加載它,并在它加載后創(chuàng)建UserModel類。
下一步,要?jiǎng)?chuàng)建擴(kuò)展自Ext.data.Store的UserStore 類:
- Ext.define('MyApp.stores.UserStore', {
- extend : 'Ext.data.Store',
- singleton : true,
- requires : ['MyApp.models.UserModel'],
- model : 'MyApp.models.UserModel',
- constructor : function() {
- this.callParent(arguments);
- this.loadData([
- {
- firstName : 'Louis',
- lastName : 'Dobbs',
- dob : '12/21/34',
- userName : 'ldobbs'
- },
- {
- firstName : 'Sam',
- lastName : 'Hart',
- dob : '03/23/54',
- userName : 'shart'
- },
- {
- firstName : 'Nancy',
- lastName : 'Garcia',
- dob : '01/18/24',
- userName : 'ngarcia'
- }
- ]);
- }
- });
當(dāng)創(chuàng)建單件模式的UserStore 時(shí),需要在UserStore原型添加一個(gè)requires關(guān)鍵字,它會(huì)在類實(shí)例化前,為ExtJS提供一個(gè)類的請(qǐng)求列表。在這個(gè)示例,列表中只有UserModel 一個(gè)請(qǐng)求類。
(實(shí)際上, 在Store的原型中定義了model為UserModel 類,ExtJS就會(huì)自動(dòng)加載它。在requires關(guān)鍵字中列出的目的,是希望你的代碼能自文檔化(self-documenting),從而提醒你,UserModel 類是必須的 )
好了,UserGridPanel視圖需要的基類已經(jīng)創(chuàng)建了,現(xiàn)在可以創(chuàng)建UserGridPanel類了:
- Ext.define('MyApp.views.UsersGridPanel', {
- extend : 'Ext.grid.Panel',
- alias : 'widget.UsersGridPanel',
- requires : ['MyApp.stores.UserStore'],
- initComponent : function() {
- this.store = MyApp.stores.UserStore;
- this.columns = this.buildColumns();
- this.callParent();
- },
- buildColumns : function() {
- return [
- {
- header : 'First Name',
- dataIndex : 'firstName',
- width : 70
- },
- {
- header : 'Last Name',
- dataIndex : 'lastName',
- width : 70
- },
- {
- header : 'DOB',
- dataIndex : 'dob',
- width : 70
- },
- {
- header : 'Login',
- dataIndex : 'userName',
- width : 70
- }
- ];
- }
- });
在上面代碼中,要注意requires 關(guān)鍵字,看它是怎么增加UserStore 為請(qǐng)求類的。剛才,我們?yōu)镚ridPanel擴(kuò)展和Store擴(kuò)展配置了一個(gè)直接的依賴關(guān)系。
下一步,我們要?jiǎng)?chuàng)建FormPanel擴(kuò)展:
- Ext.define('MyApp.views.UserFormPanel', {
- extend : 'Ext.form.Panel',
- alias : 'widget.UserFormPanel',
- bodyStyle : 'padding: 10px; background-color: #DCE5F0;'
- + ' border-left: none;',
- defaultType : 'textfield',
- defaults : {
- anchor : '-10',
- labelWidth : 70
- },
- initComponent : function() {
- this.items = this.buildItems();
- this.callParent();
- },
- buildItems : function() {
- return [
- {
- fieldLabel : 'First Name',
- name : 'firstName'
- },
- {
- fieldLabel : 'Last Name',
- name : 'lastName'
- },
- {
- fieldLabel : 'DOB',
- name : 'dob'
- },
- {
- fieldLabel : 'User Name',
- name : 'userName'
- }
- ];
- }
- });
因?yàn)閁serForm 不需要從服務(wù)器端請(qǐng)求任何類,因而不需要添加requires定義。
應(yīng)用快完成了,現(xiàn)在需要?jiǎng)?chuàng)建UserEditorWindow類和運(yùn)行應(yīng)用的app.js。以下是UserEditorWindow類的代碼。因?yàn)橐獙rid和表單綁定在一起,因而類代碼有點(diǎn)長(zhǎng),請(qǐng)見諒:
- Ext.define('MyApp.views.UserEditorWindow', {
- extend : 'Ext.Window',
- requires : ['MyApp.views.UsersGridPanel','MyApp.views.UserFormPanel'],
- height : 200,
- width : 550,
- border : false,
- layout : {
- type : 'hbox',
- align : 'stretch'
- },
- initComponent : function() {
- this.items = this.buildItems();
- this.buttons = this.buildButtons();
- this.callParent();
- this.on('afterrender', this.onAfterRenderLoadForm, this);
- },
- buildItems : function() {
- return [
- {
- xtype : 'UsersGridPanel',
- width : 280,
- itemId : 'userGrid',
- listeners : {
- scope : this,
- itemclick : this.onGridItemClick
- }
- },
- {
- xtype : 'UserFormPanel',
- itemId : 'userForm',
- flex : 1
- }
- ];
- },
- buildButtons : function() {
- return [
- {
- text : 'Save',
- scope : this,
- handler : this.onSaveBtn
- },
- {
- text : 'New',
- scope : this,
- handler : this.onNewBtn
- }
- ];
- },
- onGridItemClick : function(view, record) {
- var formPanel = this.getComponent('userForm');
- formPanel.loadRecord(record)
- },
- onSaveBtn : function() {
- var gridPanel = this.getComponent('userGrid'),
- gridStore = gridPanel.getStore(),
- formPanel = this.getComponent('userForm'),
- basicForm = formPanel.getForm(),
- currentRec = basicForm.getRecord(),
- formData = basicForm.getValues(),
- storeIndex = gridStore.indexOf(currentRec),
- key;
- //loop through the record and set values
- currentRec.beginEdit();
- for (key in formData) {
- currentRec.set(key, formData[key]);
- }
- currentRec.endEdit();
- currentRec.commit();
- // Add and select
- if (storeIndex == -1) {
- gridStore.add(currentRec);
- gridPanel.getSelectionModel().select(currentRec)
- }
- },
- onNewBtn : function() {
- var gridPanel = this.getComponent('userGrid'),
- formPanel = this.getComponent('userForm'),
- newModel = Ext.ModelManager.create({},
- 'MyApp.models.UserModel');
- gridPanel.getSelectionModel().clearSelections();
- formPanel.getForm().loadRecord(newModel)
- },
- onAfterRenderLoadForm : function() {
- this.onNewBtn();
- }
- });
UserEditorWindow 的代碼包含了許多東西用來(lái)管理UserGridPanel和UserFormPanel類的整個(gè)綁定的聲明周期。為了指示ExtJS在創(chuàng)建該類前加載這兩個(gè)類,必須在requires列表里列出它們。
現(xiàn)在完成最后一個(gè)文件app.js。為了最大限度地提高我們的學(xué)習(xí),將有3次修改要做。首先從最簡(jiǎn)單配置開始,然后逐步添加。
- Ext.Loader.setPath('MyApp', 'js/MyApp');
- Ext.onReady(function() {
- Ext.create('MyApp.views.UserEditorWindow').show();
- });
首先,app.js會(huì)在ExtJS添加MyApp命名空間的路徑,這可通過(guò)調(diào)用Ext.loader.setPath方法實(shí)現(xiàn),方法的第1個(gè)參數(shù)是命名空間,然后是加載文件與頁(yè)面的相對(duì)路徑。
下一步,調(diào)用Ext.OnReady方法,傳遞一個(gè)包含Ext.create的匿名函數(shù)。Ext.create會(huì)在ExtJS 4.0初始化之后執(zhí)行,以字符串形式傳遞的UserEditorWindow 類會(huì)被實(shí)例化。因?yàn)椴恍枰赶驅(qū)嵗拖M⒓达@示它,因而在后面串接了show方法的調(diào)用。
如果你打開這個(gè)頁(yè)面(http://moduscreate.com/senchaarticles/01/pass1.html ),你會(huì)看到UI渲染,但很慢,并且ExtJS會(huì)在Firebug中顯示以下警告信息:

ExtJS提示我們沒(méi)有使用加載系統(tǒng)最優(yōu)化的方式。這是第二步要討論的問(wèn)題。然后,這是一個(gè)好的學(xué)習(xí)機(jī)會(huì),要好好理由。
我們需要配置Firebug在控制臺(tái)中顯示XHR請(qǐng)求,以便在控制臺(tái)中看到所有請(qǐng)求,而不需要切換到網(wǎng)絡(luò)面板。這樣,我們不單可以觀察到類依賴系統(tǒng)的工作情況,還可以從所有ExtJS類加載的文件中通過(guò)過(guò)濾方式找到我們要求這樣的文件。
在Firebug控制臺(tái)過(guò)濾輸入框中輸入“User”,你會(huì)看到下圖所示的結(jié)果。
從圖中可以看到,UserEditorWindow類第一個(gè)被加載,接著請(qǐng)求UserGridPanel。UserGridPanel 要求UserStore和UserModel類。最后加載UserFormPanel 類。
我剛才提到,ExtJS提示了我們沒(méi)有使用加載系統(tǒng)最優(yōu)化的方式。這是因?yàn)橐蕾囀窃贓xt.OnReady觸發(fā)加載之后通過(guò)同步XHR請(qǐng)求確定的,而這不是有效的方式且難于調(diào)試。
未來(lái)修正這個(gè)問(wèn)題,可以修改app.js指示ExtJS先加載我們定義的類,這樣即可提供性能又便于調(diào)試:
- Ext.Loader.setPath('MyApp', 'js/MyApp');
- Ext.require('MyApp.views.UserEditorWindow');
- Ext.onReady(function() {
- Ext.create('MyApp.views.UserEditorWindow').show();
- });
為了快速加載我們定義的類和避免調(diào)試信息,可簡(jiǎn)單的在Ext.onReady前調(diào)用Ext.require,只是ExtJS請(qǐng)求 UserEditorWindow類。這將會(huì)讓ExtJS在文檔HEAD標(biāo)記內(nèi)注入一個(gè)script標(biāo)記,運(yùn)行資源在Ext.OnReady前加載。
查看http://moduscreate.com/senchaarticles/01/pass2.html 可看到它是如何工作地。在頁(yè)面加載后,你會(huì)注意到ExtJS沒(méi)有在控制臺(tái)顯示警告信息了。
我們所做的是讓ExtJS框架和應(yīng)用類延遲加載。雖然這樣做調(diào)試很好,但是對(duì)于需要快速調(diào)試的情況,頁(yè)面渲染時(shí)間會(huì)讓你感到痛苦。為什么?
原因很簡(jiǎn)單,因?yàn)檫@需要加載許多資源文件。在示例中,ExtJS發(fā)送了193個(gè)Javascript資源請(qǐng)求到web服務(wù)器,還有部分是在緩存中的:

我們創(chuàng)建了6個(gè)Javascript文件(5個(gè)類文件和app.js),這意味著加載要求的ExtJS文件有187個(gè)請(qǐng)求。當(dāng)你在本地做開發(fā)的時(shí)候,這個(gè)方案可行,但不是最理想的和效果最好的。
解決這個(gè)問(wèn)題,我們可以使用折中方案,通過(guò)ext-all-debug加載ExtJS框架,動(dòng)態(tài)加載我們的類文件。要實(shí)現(xiàn)這個(gè),需要修改兩個(gè)文件。
- <script type="text/javascript" src="js/ext-4.0.1/ext-all-debug.js"></script>
首先,需要修改Index.html,使用ext-all-debug.js替換ext.debug.js。
接著,修改app.js,開啟Ext.Loader:
- (function() {
- Ext.Loader.setConfig({
- enabled : true,
- paths : {
- MyApp : 'js/MyApp'
- }
- });
-
- Ext.require('MyApp.views.UserEditorWindow');
-
- Ext.onReady(function() {
- Ext.create('MyApp.views.UserEditorWindow').show();
- });
- })();
通過(guò)調(diào)用Loader.setConfig可開啟Ext.Loader,需要傳遞一個(gè)匿名對(duì)象,它的eanbled屬性設(shè)置為true,而命名空間設(shè)置為路徑映射。
通過(guò)編輯app.js,在本地開發(fā)環(huán)境下,應(yīng)用將會(huì)在1秒內(nèi)完成加載和渲染。

源代碼下載地址:http://moduscreate.com/senchaarticles/01/files.zip
譯文鏈接地址:blog.csdn.net/tianxiaode/archive/2011/06/28/6571589.aspx