EXTjsMVC应用架构.docx
- 文档编号:12714410
- 上传时间:2023-04-21
- 格式:DOCX
- 页数:19
- 大小:317.91KB
EXTjsMVC应用架构.docx
《EXTjsMVC应用架构.docx》由会员分享,可在线阅读,更多相关《EXTjsMVC应用架构.docx(19页珍藏版)》请在冰豆网上搜索。
EXTjsMVC应用架构
MVC应用架构
大型客户端程序总是很难编写、组织和维护。
当你加入更多功能和开发者到一个项目中时,它们就会迅速膨胀失去控制。
ExtJS4带来了一个新的程序架构,它不但帮你组织代码而且件事你需要些的代码数量。
我们的程序架构参照MVC模式,模板和控制器被首先提出。
现在有许多MVC架构,都是大同小异。
我们是这样定义的:
模型(Model)是域与数据的集合。
模型知道如何通过数据包的方式保留它们,并且能够通过关联被其他模型链接。
是ExtJS3中的Record的改进版,并且一般与Stores一同使用来给grids或其他组件提供数据。
视图(View)是任意的组件,grids,tree和panel都是views。
控制器(Controllers)是比较特别,来决定你的应用程序是否显示视图,初始化模型和其他应用逻辑。
在这篇指导中,我们会创建一个非常简单的应用来管理用户数据。
在最后你将会知道如何运用ExtJS4程序架构把简单的应用放到一起。
应用架构是关于提供结构与组成,也是关于真实的类与框架代码。
沿用这些约定能获得许多重要的好处:
每个应用以同样的方式工作,所以你只需要学习一次
在工作方式相同的应用之间共享代码更容易
你能使用我们的工具为产品应用创建完善的程序版本
文件结构
ExtJS4应用程序遵循一个对于所有应用都统一的目录结构。
针对应用程序关于基本文件结构的详细解释请参考起步·指南。
在MVC布局方面,所有的类都被放置在app目录下,该目录依次包含你的模板、视图、控制器和存储的命名空间。
下面是当我们完成一个简单示例应用时目录结构的组织方式。
在这个例子中,我们把所有的应用文件都放到了一个叫做account_manager的文件夹下。
必要的ExtJS4SDK文件被包含进ext-4.0目录下。
然后我们的index.html的内容如下所示:
在app.Js中创建应用
每个ExtJS4应用都以一个应用类实例开始。
该应用包含全局设置,也包含对所有被应用使用的模板、视图和控制器的引用。
以及一个当所有组件都载入后自动执行的载入函数。
让我们创建一个简单的帮助我们管理用户帐户的账户管理应用。
首先我们需要为这个应用选择一个全局的命名空间。
所有的ExtJS4应用应该只使用一个全局变量,所有的应用类都包含在其中。
通常我们需要一个简短的全局变量所以在这个应用中我们打算使用“AM”:
首先我们调用了Ext.Application来创建一个应用实例并赋予了命名空间"AM"。
这为我们自动设置了一个全局变量AM,并且向Ext.Loader注册了该命名空间,通过appFolder配置选项获得了交互目录"app"。
我们也提供了一个简单的载入函数,只创建了包含一个简单的全屏的panel的Viewport:
Ext.application({
name:
'AM',
appFolder:
'app',
launch:
function(){
Ext.create('Ext.container.Viewport',{
layout:
'fit',
items:
[{
xtype:
'panel',
title:
'Users',
html:
'Listofuserswillgohere'
}]
});
}
});
定义一个控制器
控制器是一种把应用所有的操作绑在一起的粘合剂。
它们所做的全部事情就是监听时间(通常来自视图)并且采取一些行动。
继续我们的账户管理应用,让我们创建一个控制器。
创建一个文件叫做app/controller/Users.Js并加入如下代码:
Ext.define('AM.controller.Users',{
extend:
'Ext.app.Controller',
init:
function(){
console.log('初始化用户!
在app.launch之前被调用');
}
});
增加新创建的Users控制器到应用配置文件app.Js中:
Ext.application({
…
controllers:
['Users']
…
});
当我们通过浏览器访问index.Html载入我们的应用时,Users控制器自动载入(因为我们在上面应用定义的时候指定过它),并且它的init函数在应用的launch函数调用之前调用。
init函数是一个绝好的地方来设置你的控制器如何与视图交互,并且通常被用来与另外的控制器函数联接。
Control函数使监听视图类上的时间和使用handler函数采取相应行动变得简单。
让我们更新一下Users控制器来告诉我们panel什么时候被放置。
Ext.define('AM.controller.Users',{
extend:
'Ext.app.Controller',
init:
function(){
this.control({
'viewport>panel':
{
render:
this.onPanelRendered
}
});
},
onPanelRendered:
function(){
console.log('Thepanelwasrendered');
}
});
我们已经更新了init函数来使用this.Control来设置对应用中的视图的监听。
Control函数使用新的ComponentQuery引擎来快速容易地得到页面上组件的引用。
如果你还不熟悉ComponentQuery,一定要去完整地看一下ComponentQuery文档。
简单说,它允许我们传递一个类似Css的能够在页面中找到所有的匹配的组件的选择字符串。
在上述我们的init函数中我们使用了“viewport>panel”,这可以转换成“帮我找到所有的Viewport的直接panel子孩子”。
我们然后采用一个映射事件名称到句柄函数的对象(当前就是render)。
这全部的结果就是不论何时匹配选择器的所有组件触发一个render事件,我们的onPanelRendered函数都会被调用。
当我们执行我们的程序会看到下图:
虽然不是最令人兴奋的应用,但是它显示了采用有组织的代码是多么容易。
现在让我们通过增加一个grid表格来丰富一下我们的应用。
定义一个视图
现在我们想要增加一个网格来显示我们系统的所有用户,是时候更好地整理一下我们的逻辑然后开始使用视图。
一个视图无非就是一个组件,通常被定义为ExtJS组件的子类。
我们打算通过建立一个叫做app/view/user/List.js的文件来创建显示用户的网格,将下列代码写入该文件:
Ext.define('AM.view.user.List',{
extend:
'Ext.grid.Panel',
alias:
'widget.userlist',
title:
'AllUsers',
initComponent:
function(){
this.store={
fields:
['name','email'],
data:
[
{name:
'Ed',email:
'ed@'},
{name:
'Tommy',email:
'tommy@'}]
};
this.columns=[
{header:
'Name',dataIndex:
'name',flex:
1},
{header:
'Email',dataIndex:
'email',flex:
1}];
this.callParent(arguments);
}
});
我们的视图类不过是一个普通的类。
目前我们恰好继承了Grid组件并且设置了一个别名以使我们能把它当做一个xtype来使用(不仅如此)。
我们也传入了store配置和网格应该有的columns。
下一步我们把这个视图加到我们的Users控制器中。
因为我们设置了‘widget’形似的别名,我们可以使用'userlist'作为一个xtype,就像我们之前使用'panel'一样。
Ext.define('AM.controller.Users',{
extend:
'Ext.app.Controller',
views:
['user.List'],
init:
...
onPanelRendered:
...
});
修改app.js中的launch方法把它加入到viewport中:
Ext.application({
...
launch:
function(){
Ext.create('Ext.container.Viewport',{
layout:
'fit',
items:
{xtype:
'userlist'}
});
}
});
这里仅需要注意我们在视图数组中声明了'user.List'。
这告诉应用程序去自动加载文件以便我们执行launch时可以使用它。
应用程序使用ExtJS4的心的动态载入系统来自动从服务器拉取该文件。
下面是我们现在刷新页面看到的:
控制表格
注意我们的onPanelRendered函数仍然被调用。
这是因为我们的grid类仍然匹配“viewport>panel”选择器。
原因是我们们的类继承了Grid,而grid继承Panel。
让我们通过使用新的xtype来把范围缩小一些。
让我们在表格行上监听双击以便我们随后编辑用户。
Ext.define('AM.controller.Users',{
extend:
'Ext.app.Controller',
views:
['user.List'],
init:
function(){
this.control({
'userlist':
{itemdblclick:
this.editUser}
});
},
editUser:
function(grid,record){
console.log('Doubleclickedon'+record.get('name'));
}
});
注意我们改变了组建选择器(变成了简单的“userlist”),事件名(“itemdblclick”)和处理函数名(“editUser”)。
目前我们只是打出了我们双击的用户名字。
我们再定义Ext.window.Window的子类,再一次使用了initComponent来配置复杂的对象items和buttons。
我们使用了一种“fit”的布局并且一个表单作为一个单独的item,这个表单包含了编辑名字和邮箱地址的区域。
最后我们创建了两个按钮,一个用来关闭窗口,一个用来保存变化信息。
我们现在只需要做的是把这个视图加入到控制器中,放置它并且载入用户信息到视图中。
要真正地编辑我们的用户,需要app/view/user/Edit.js:
Ext.define('AM.view.user.Edit',{
extend:
'Ext.window.Window',
alias:
'widget.useredit',
title:
'EditUser',
layout:
'fit',
autoShow:
true,
initComponent:
function(){
this.items=[{
xtype:
'form',
items:
[
{xtype:
'textfield',name:
'name',fieldLabel:
'Name'},
{xtype:
'textfield',name:
'email',fieldLabel:
'Email'}
]
}];
this.buttons=[
{text:
'Save',action:
'save'},
{text:
'Cancel',scope:
this,handler:
this.close}
];
this.callParent(arguments);
}
});
Ext.define('AM.controller.Users',{
extend:
'Ext.app.Controller',
views:
['user.List','user.Edit'],
init:
...
editUser:
function(grid,record){
varview=Ext.widget('useredit');
view.down('form').loadRecord(record);
}
});
首先我们使用便利的方法Ext.widget创建了视图,该方法与Ext.create('widget.useredit')等价。
然后我们再次使用组件选择快速得到引用来编辑窗口中的表单。
每个组件在ExtJS4中都有一个down函数,该函数接受一个组件选择字符串来快速找到任何孩子组件。
在我们的表格中双击一行现在出现了像下面的情景:
创建一个模型(Model)和仓库(Store)
现在有了编辑表单,几乎是时候开始编辑我们的用户并且保存变化信息。
在这么做之前,我们应该重构一下代码。
AM.view.user.List组件内部创建了一个Store。
这样运行得很好但是我们想要无论在程序的什么地方都能引用这个Store以便我们能改变其中的数据。
我们开始把Store分离到它自己的文件中——app/store/User.js:
Ext.define('AM.store.Users',{
extend:
'Ext.data.Store',
fields:
['name','email'],
data:
[
{name:
'Ed',email:
'ed@'},
{name:
'Tommy',email:
'tommy@'}
]
});
现在我们仅仅需要改变两个小地方——首先我们命令Users控制器在载入的时候包含这个Store:
Ext.define('AM.controller.Users',{
extend:
'Ext.app.Controller',
stores:
['Users'],
...
});
然后我们更新app/view/user/List.js来简单通过id来引用Store:
Ext.define('AM.view.user.List',{
extend:
'Ext.grid.Panel',
alias:
'widget.userlist',
//不需要在`initComponent`方法中定义Usersstore了
store:
'Users',
...
});
通过在Users控制器中定义中包含所需要的Store,Store会自动载入到页面并被分配一个storeid,这使他们在视图中方便被引用(在当前简单通过配置store:
'Users')。
同时我们在store中定义了我们的字段('name'和'email')。
这运行得很好,但是在ExtJS4中我们有一个更强大的Ext.data.Model类,当编辑我们的用户时我们想要利用它。
我们将会通过重构我们的Store使用Model来结束这一章,我们将会在app/model/User.js放入如下内容:
Ext.define('AM.model.User',{
extend:
'Ext.data.Model',
fields:
['name','email']
});
上述那些就是我们定义模型(model)所需要做的一切,现在我们来更新Store引用模型而不是内部提供字段,并且使用户控制器也获得对模型的引用:
//Userscontroller会识别Usermodel
Ext.define('AM.controller.Users',{
extend:
'Ext.app.Controller',
stores:
['Users'],
models:
['User'],
...
});
//引用Model而不是在内部定义
Ext.define('AM.store.Users',{
extend:
'Ext.data.Store',
model:
'AM.model.User',
data:
[
{name:
'Ed',email:
'ed@'},
{name:
'Tommy',email:
'tommy@'}
]
});
使用模板保存数据
现在我们来保存用户做出的改变。
上面定义的编辑用户窗口包含了一个表单(有name和email字段),和一个保存按钮。
首先更新控制器的init函数来监听保存按钮的点击事件:
Ext.define('AM.controller.Users',{
init:
function(){
this.control({
'viewport>userlist':
{itemdblclick:
this.editUser},
'usereditbutton[action=save]':
{click:
this.updateUser}
});
},
updateUser:
function(button){
console.log('clickedtheSavebutton');
}
});
我们control函数增加了第二个组件选择器
('usereditbutton[action=save]')。
这和第一个选择器以同样的方式工作——它使用我们在上面定义的用来聚焦我们编辑用户窗口的'useredit'xtype,然后在窗口中寻找带有属性值为save的action属性的按钮。
当我们定义编辑用户窗口,我们传了{action:
'save'}给保存按钮,这给了我们一个容易的方法来定位按钮。
点击保存按钮时调用updateUser函数被调用:
现在我们看到函数正确关联到保存按钮的点击事件,让我们为updateUser函数写入真正的逻辑。
在函数中我们需要从表单中获得数据,更新用户视图,然后将我们填入的信息保存到用户store中。
具体来看:
我们的点击事件给予我们点击按钮的引用,但是我们真正想要的是访问包含数据的表单和窗口本身。
为了让事情变得简单我们再次使用组件选择器,首先使用botton.up('window')来得到编辑用户窗口的引用,然后使用win.down('form')来得到表单。
updateUser:
function(button){
varwin=button.up('window'),
form=win.down('form'),
record=form.getRecord(),
values=form.getValues();
record.set(values);
win.close();
}
在这之后我们简单地得到表单中的数据记录并且使用用户输入到表单的数据更新它。
最后我们关闭窗口来把关注点移到表格。
下面是我们再次运行程序看到的,改变名字字段为'Ed Spencer'并且点击保存。
保存到服务器
很简单。
让我们使程序与我们的服务器端联系来结束。
在我们艰难地敲入用户记录到用户存储器(Store)中的同时,让我们通过AJAJ来读取:
Ext.define('AM.store.Users',{
extend:
'Ext.data.Store',
model:
'AM.model.User',
autoLoad:
true,
proxy:
{
type:
'ajax',
url:
'data/users.json',
reader:
{
type:
'json',
root:
'users',
successProperty:
'success'
}
}
})
这里我们取消了'data'属性并用了一个(代理)Proxy代替。
在ExtJS4中代理是载入和保存来自一个存储器或者模板数据的方式。
其他代理方式还有AJAX,JSON-P和HTML5本地存储。
这里我们使用一个简单的AJAX代理,我们让它从'data/users.json'载入数据。
我们也给代理关联了一个reader。
这个reader负责将服务器端返回的数据解析成存储器(Store)能够理解的数据格式。
这次我们使用了JSON reader,并且指定了root和successProperty配置(查阅JsonReader文档来获取更多配置信息)。
最后我们创建data/users.json文件并粘贴先前的数据进去:
{
success:
true,
users:
[
{id:
1,name:
'Ed',email:
'ed@'},
{id:
2,name:
'Tommy',email:
'tommy@'}
]
}
我们所做的唯一改变时设置了autoLoad为true,这意味着存储器会让代理立刻载入数据。
如果我们刷新页面,我们会看到相同的效果。
在这里我们最后需要做的是把变化的数据回传给服务器。
这需要我们在updateUser函数中增加几行,如下所示:
updateUser:
function(button){
…
win.close();
this.getUsersStore().sync();
}
也许还需要新的URL
proxy:
{
type:
'ajax',
api:
{
read:
'data/users.json',
update:
'data/updateUsers.json'
},
reader:
{
type:
'json',
root:
'users',
successProperty:
'success'
}
}
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- EXTjsMVC 应用 架构