在Extjs4应用中使用Ext.Loader

在开始之前,我们先来看看将要实现的结果。这样做,可使我们确定需要扩展那些类。

应用会包括互相绑定的GridPanel和FormPanel,名称分别为UserGridPanel和UserFormPanel。UserGridPanel的操作需要创建一个模型和Store。UserGridPanel和UserFormPanel将被渲染到一个名称为UserEditorWindow的窗口,它扩张自extjs的Window类。所有这些类都会在命名空间MyApp下。
在开始编码前,首先要确定目录结构,以下是使用命名空间组织的文件夹:

从上图可以看到,MyApp目录已经按照命名空间进拆分成几个目录。在完成开发的时候,我们的应用将会有一个如下图所示的内部依赖运行模型。
尽管应用的目录构成很象extjs 4 MVC架构,事实上示例并没有使用它 

现在开始编写index.html文件,这里需要包含应用需要的启动文件和应用的根文件(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标记包含 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:

  • Ext.define('MyApp.models.UserModel', {
  •     extend   : 'Ext.data.Model',
  •     fields   : [
  •         'firstName',
  •         'lastName',
  •         'dob',
  •         'userName'
  •     ]
  • });



以上代码扩展自Ext.data.Model,将创建UserModel 类。因为扩展自Ext.data.Model类, extjs会自动加载它,并在它加载后创建UserModel类。
下一步,要创建扩展自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'
  •             }
  •         ]);
  •     }
  • });



当创建单件模式的UserStore 时,需要在UserStore原型添加一个requires关键字,它会在类实例化前,为 extjs提供一个类的请求列表。在这个示例,列表中只有UserModel 一个请求类。
(实际上, 在Store的原型中定义了model为UserModel 类,ExtJS就会自动加载它。在requires关键字中列出的目的,是希望你的代码能自文档化(self-documenting),从而提醒你,UserModel 类是必须的 )
好了,UserGridPanel视图需要的基类已经创建了,现在可以创建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 关键字,看它是怎么增加UserStore 为请求类的。刚才,我们为GridPanel扩展和Store扩展配置了一个直接的依赖关系。
下一步,我们要创建FormPanel扩展:

  • 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'
  •             }
  •         ];
  •     }
  • });



因为UserForm 不需要从 服务器端请求任何类,因而不需要添加requires定义。
应用快完成了,现在需要创建UserEditorWindow类和运行应用的app.js。以下是UserEditorWindow类的代码。因为要将Grid和表单绑定在一起,因而类代码有点长,请见谅:

  • 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 的代码包含了许多东西用来管理UserGridPanel和UserFormPanel类的整个绑定的声明周期。为了指示ExtJS在创建该类前加载这两个类,必须在requires列表里列出它们。
现在完成最后一个文件app.js。为了最大限度地提高我们的学习,将有3次修改要做。首先从最简单配置开始,然后逐步添加。

  • Ext.Loader.setPath('MyApp', 'js/MyApp');
  • Ext.onReady(function() {
  •     Ext.create('MyApp.views.UserEditorWindow').show();
  • });



首先,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.html ),你会看到UI渲染,但很慢,并且ExtJS会在Firebug中显示以下警告信息:

ExtJS提示我们没有使用加载系统最优化的方式。这是第二步要讨论的问题。然后,这是一个好的学习机会,要好好理由。
     我们需要配置Firebug在控制台中显示XHR请求,以便在控制台中看到所有请求,而不需要切换到网络面板。这样,我们不单可以观察到类依赖系统的工作情况,还可以从所有ExtJS类加载的文件中通过过滤方式找到我们要求这样的文件。
     在Firebug控制台过滤输入框中输入“User”,你会看到下图所示的结果。
从图中可以看到,UserEditorWindow类第一个被加载,接着请求UserGridPanel。UserGridPanel 要求UserStore和UserModel类。最后加载UserFormPanel 类。
我刚才提到,ExtJS提示了我们没有使用加载系统最优化的方式。这是因为依赖是在Ext.OnReady触发加载之后通过同步XHR请求确定的,而这不是有效的方式且难于调试。
未来修正这个问题,可以修改app.js指示ExtJS先加载我们定义的类,这样即可提供性能又便于调试:

  • Ext.Loader.setPath('MyApp', 'js/MyApp');
  • Ext.require('MyApp.views.UserEditorWindow');
  • Ext.onReady(function() {
  •     Ext.create('MyApp.views.UserEditorWindow').show();
  • });



为了快速加载我们定义的类和避免调试信息,可简单的在Ext.onReady前调用Ext.require,只是ExtJS请求UserEditorWindow类。这将会让ExtJS在文档HEAD标记内注入一个script标记,运行资源在Ext.OnReady前加载。
查看 http://moduscreate.com/senchaarticles/01/pass2.html 可看到它是如何工作地。在页面加载后,你会注意到ExtJS没有在控制台显示警告信息了。
我们所做的是让ExtJS框架和应用类延迟加载。虽然这样做调试很好,但是对于需要快速调试的情况,页面渲染时间会让你感到痛苦。为什么?
原因很简单,因为这需要加载许多资源文件。在示例中,ExtJS发送了193个 javascript资源请求到web 服务器,还有部分是在缓存中的:

我们创建了6个 javascript文件(5个类文件和app.js),这意味着加载要求的ExtJS文件有187个请求。当你在本地做开发的时候,这个方案可行,但不是最理想的和效果最好的。
解决这个问题,我们可以使用折中方案,通过ext-all-debug加载ExtJS框架,动态加载我们的类文件。要实现这个,需要修改两个文件。

  • <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();
  •     });
  • })();



通过调用Loader.setConfig可开启Ext.Loader,需要传递一个匿名对象,它的eanbled属性设置为true,而命名空间设置为路径映射。
通过编辑app.js,在本地开发环境下,应用将会在1秒内完成加载和渲染。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值