MVC架构
大客户端应用程序一直难写,难以组织和难以维持。他们往往迅速增长失控,为您添加更多的功能和开发项目。Ext JS的4配备了一个新的应用架构,不仅组织你的代码,但减少的金额,你必须写。
我们的应用架构如下首次推出的模型和控制器的MVC状花纹。有许多的MVC架构,其中大部分是从一个略有不同。下面是我们如何定义我们的:
-
模型是一个领域,他们的数据(例如,一个用户的用户名和密码字段模型)的集合。模型知道如何坚持自己的数据包通过,并通过协会可以与其他车型。模型的工作很多像Ext JS的3条记录类,通 常用于存储提交到电网和其他组件的数据
-
视图是任何类型的组件-网格,树木和面板的所有意见。
-
控制器是特殊的地方,把所有的代码,使您的应用程序工作-无论是渲染视图,实例模型,或任何其他应用程序逻辑。
在本指南中,我们将创建一个非常简单的应用程序,管理用户数据。截至去年底,你就会知道如何把简单的应用程序一起使用新的Ext JS的应用架构。
应用程序架构提供结构和一致性,因为它是实际的类和框架代码是多少。按照公约,释放一些重要的好处:
- 每个应用程序的工作方式相同,所以你只需要学习一次
- 因为他们都以同样的方式工作,很容易在应用程序之间共享代码
- 您可以使用我们建立的工具来创建您的应用程序的优化版本,用于生产
文件结构
Ext JS的应用程序遵循一个统一的,是为每一个应用程序相同的目录结构。请入门指南应用程序的基本文件结构上进行了详细的解释。MVC中的布局,所有的类都放置到应用程序
文件夹,这反过来又包含子文件夹的命名空间的模型,视图,控制器和存储。下面是如何简单的例子,应用程序的文件夹结构看时,我们就大功告成了:
在这个例子中,我们称为“一个文件夹内封装整个应用程序account_manager
“。EXT-4.0
文件夹裹在里面的重要文件的Ext JS 4 SDK。因此,我们的内容的index.html
看起来像这样:
<HTML>
<HEAD>
<TITLE> 客户经理</ TITLE>
<链接 REL = “样式” 类型= “文本/ CSS” HREF = “ext-4.0/resources/css/ext-all.css” >
<脚本 类型= “文本/ javascript” SRC = “ext-4.0/ext-debug.js” > </ SCRIPT>
<脚本 类型= “文本/ javascript” SRC = “app.js” > </ SCRIPT>
</ HEAD>
<BODY> </ BODY>
</ HTML>
创建应用app.js
每Ext JS的应用程序的启动与应用程序类的一个实例。该应用程序包含全局设置为您的应用程序(如应用程序的名称),以及维护所有的模型,视图和应用程序所使用的控制器的引用。应用程序还包含一个发射功能,这是自动运行一切是loaded.B时
让我们创建一个简单的帐户管理应用程序,将帮助我们管理用户帐户。首先,我们需要为这个应用挑选一个全局命名空间。所有的Ext JS 4应用程序应该只使用一个单一的全局变量,它里面嵌套的应用程序的类。通常,我们希望有一个短的全局变量,所以在这种情况下,我们要使用的“AM”:
分机。应用({
名字: “AM” ,
appFolder : “应用程序” ,
用户将在这里去'
}
]
});
} } );
有几件事情是怎么回事。首先,我们调用Ext.application
创建一个新的应用程序类的实例,这是我们通过的名称为“ AM
“。这将自动设置一个全局变量上午
我们,注册命名空间Ext.Loader
与相应的路径,应用程序
通过集appFolder
配置选项。我们还提供了一个简单的发射功能,只是创建一个视口,其中包含一个单一的面板,将填补屏幕。
定义控制器
控制器应用程序绑定在一起的胶水。他们真的是监听事件(通常是从意见),并采取一些行动。继续我们的帐户管理器应用程序,让我们创建一个控制器。创建文件APP /控制器/ Users.js的的,
并添加以下代码:
分机定义(“AM.controller.Users' , {
延长: “Ext.app.Controller” ,
的init () {
控制台日志(此之前发生的应用推出功能被称为“初始化用户!” );
} } );
现在让我们添加我们新创建的用户控制器到在app.js的应用程序配置:
分机应用({
...
控制器: [
'用户'
],
...
});
当我们加载访问我们的应用程序在浏览器中的index.html
,用户
控制器自动加载(因为我们在应用上述定义指定),其init
函数之前调用应用程序的启动
功能。
init 函数是一个伟大的地方设立控制器与视图的交互如何,通常是在与另一个控制器功能结合使用- 控制。控制
功能,使得容易听你的视图类的事件处理函数,并采取一些行动。让我们更新我们的用户
控制器呈现面板时告诉我们:
分机定义(“AM.controller.Users' , {
延长: “Ext.app.Controller” ,
初始化 函数() {
。控制({
“视口”面板“ : {
渲染: 这一点。onPanelRendered
} } );
}
onPanelRendered : 函数() {
控制台。日志(“面板,呈现” );
}
});
我们已经更新了init
函数使用this.control
成立听众在我们的应用程序的意见。控制
功能使用新ComponentQuery引擎,快速,方便地获取页面上的组件的引用。如果你是不是还熟悉与ComponentQuery的,是一定要检查出ComponentQuery文件为一个完整的解释。虽然短暂,它使我们能够通过一个CSS样的选择,会发现页面上的每一个匹配元件。
在我们上面init函数中,我们提供的“视口>面板”
,翻译“找到我每一个小组,这是一个视口的直接子”。然后,我们提供了一个对象,事件名称映射(只是呈现
在这种情况下)处理函数。整体效果是,只要符合我们的选择火灾渲染
事件的任何组件,我们onPanelRendered
函数被调用。
当我们运行我们的应用程序,现在我们看到以下:
不完全是有史以来最令人兴奋的应用,但它显示了它是多么容易得到有组织的代码开始。让我们的血肉了一个小的应用程序,现在增加一格。
定义一个视图
到现在为止我们的应用程序仅是一个漫长的几行,只栖息在两个文件- app.js
APP /控制器/ Users.js的的
。现在我们要添加一个网格,呈现在我们的系统中的所有用户,它的时间来组织我们的逻辑好一点,并开始使用意见。
一种观点是什么比通常作为一个Ext JS的组件的一个子类中定义的组件,。我们将通过创建一个新文件创建现在我们的用户电网的应用程序/视图/用户/ List.js
并把它下面:
分机定义(“AM.view.user.List' ,{
延长 “Ext.grid.Panel' ,
别名 : “widget.userlist”
标题: “所有用户” ,
initComponent: function() {
this.store = {
fields: ['name', 'email'],
data : [
{name: 'Ed', email: 'ed@sencha.com'},
{name: 'Tommy', email: 'tommy@sencha.com'}
]
};
列= [
{ 头: '名称' , dataIndex : '名称' , 柔性: 1 },
{ 头: “电子邮件” ,dataIndex : “电子邮件” ,柔性: 1 }
];
。callParent (参数);
} } );
我们认为类是没有超过一个普通的类。在这种情况下,我们发生扩展的网格组件,并设置一个别名,使我们可以使用它作为一个的xtype(在某一时刻,更多)。我们还通过在存储配置和电网应给予的列。
下一步,我们需要添加这种观点,我们的用户
控制器。因为我们设置的别名,使用特殊的部件。
格式,我们可以使用“用户列表”作为一个的xtype现在,就像我们以前曾使用“面板”
。
分机定义(“AM.controller.Users' , {
延长: “Ext.app.Controller” ,
意见: [
'user.List'
],
初始化: ...
onPanelRendered : ...
});
主视口内发射法的修改,然后渲染app.js
到:
分机应用({
...
发射: 函数() {
分机创建(“Ext.container.Viewport ,
布局: 适合“ ,
项目: {
的xtype : '会员列表'
}
});
} } );
唯一的其他东西,这里要注意的是,我们指定“user.List
意见数组内。这告诉应用程序自动加载该文件,使我们可以使用它,当我们推出。应用程序使用Ext JS的4个新的动力加载系统自动从这个文件服务器。这里我们看到,当我们现在刷新页面:
控制网格
注意我们onPanelRendered
功能仍然被称为。这是因为我们的电网类仍然匹配“视口>面板的
选择。这样做的原因是我们班的延伸电网,进而扩展面板。
此刻,我们加入到这个选择的听众,实际上将被称为每一个小组或小组的子类,它是一个视口的直接子,让我们紧了一下使用我们新的xtype。虽然我们在这时候,让我们听,而不是双击网格中的行,使我们可以在以后编辑该用户:
分机定义(“AM.controller.Users' , {
延长: “Ext.app.Controller” ,
意见: [
'user.List'
],
初始化 函数() {
。控制({
“用户列表” : {
itemdblclick 。editUser
}
});
}
editUser : 功能(网格,记录) {
控制台日志(“双击” + 纪录。获得('名称' ));
} } );
请注意,我们改变的ComponentQuery选择(简单的“用户列表”
),事件的名称(为“itemdblclick”
)和处理函数的名称(到“editUser”
)。现在我们只是记录了我们双击用户名:
记录到控制台是一切都很好,但我们真的要编辑我们的用户。让我们做一个新的观点,现在,启动应用程序/视图/用户/ Edit.js
:
分机定义(“AM.view.user.Edit' , {
延长: “Ext.window.Window” ,
别名 : “widget.useredit”
标题: “编辑用户” ,
布局: '适合' ,
车展: 真实,
initComponent: function() {
this.items = [
{
xtype: 'form',
items: [
{
xtype: 'textfield',
name : 'name',
fieldLabel: 'Name'
},
{
xtype: 'textfield',
name : 'email',
fieldLabel: 'Email'
}
]
}
];
按钮= [
{
文字: “保存” ,
行动: “保存”
},
{
文字: '取消' ,
范围 ,
处理程序: 此。}
];
。callParent (参数);
} } );
再次,我们只是定义现有组件的一个子类-这个时候Ext.window.Window
。一旦我们使用initComponent
指定复杂对象的项目
和按钮
。我们用一个'适合'的
布局和形式为单个项目,其中包含的字段编辑的姓名和电子邮件地址。最后,我们创建了两个按钮,一个刚刚关闭该窗口,将被用来拯救我们的变化。
我们现在要做的是添加视图控制器,使其加载到它的用户:
分机定义(“AM.controller.Users' , {
延长: “Ext.app.Controller” ,
意见: [
'user.List“ ,
'user.Edit'
],
初始化: ...
editUser : (网格,记录) {
VAR 视图= 分机。部件(“useredit );
查看。(“形式” 。)loadRecord (纪录);
} } );
首先,我们创建的视图,使用的方便的的方法Ext.widget
,这相当于到Ext.create(“widget.useredit)
。然后,我们的杠杆ComponentQuery一次更迅速获得编辑窗口的形式。在Ext JS 4的每一个组件都有一个向下的
函数,它接受一个ComponentQuery迅速找到任何子组件的选择。
现在双击一下一排在我们的电网,产生这样的事情:
创建一个模型和一个商店
现在,我们有我们的编辑形式,它的时间差不多了,开始编辑我们的用户,并保存这些改变。之前,我们这样做,虽然,我们应该重构我们的代码一点点。
此刻AM.view.user.List
组件创建一个商店内联。这工作得很好,但我们希望能够到其他地方引用,商店中的应用,使我们可以更新它的数据。我们将开始分解成它自己的文件出了店门- APP /店/ Users.js的的
:
Ext.define('AM.store.Users', {
extend: 'Ext.data.Store',
fields: ['name', 'email'],
data: [
{name: 'Ed', email: 'ed@sencha.com'},
{name: 'Tommy', email: 'tommy@sencha.com'}
]
});
现在,我们就做2小的变化-首先,我们将要求我们的用户
控制器包括此店铺,当它加载:
分机定义(的“AM.controller.Users' , {
延长的 “Ext.app.Controller' ,
商店: [
'用户'
],
...
});
然后,我们将更新程序/视图/用户/ List.js的
简单地引用ID的商店:
分机定义(“AM.view.user.List' ,{
延长 “Ext.grid.Panel' ,
别名 : “widget.userlist”
/ /我们不再定义在`initComponent方法的用户店
店: “用户” ,
...
});
包括商店,关心我们的用户
控制器在其定义中,它们自动加载到页面上,并给予StoreID的,这使得它们很容易在我们的意见引用(通过简单的配置存储:
在这种情况下,“用户”
)。
目前,我们刚刚定义的领域(“名”
和“电子邮件”
),在商店内联。此作品不够好,但在Ext JS 4,我们有一个的强大Ext.data.Model
类,我们想利用当它来编辑我们的用户。我们将结束本节,通过重构我们的商店使用一个模型,我们将在
app /模型/ user.js文件一样
:
分机定义(“AM.model.User' , {
延长:的 “Ext.data.Model' ,
字段: [ '名称' , '电子邮件' ]
});
这就是所有我们需要做的定义我们的模型,现在我们就更新我们的商店提供领域内联,而不是引用的型号名称,并要求用户
控制器得到参考模型:
/ /用户控制器将确保用户模型包含在页面上提供给我们的
/ /我们现在引用的模型,而不是定义领域内联
内线。定义(的“AM.store.Users' , {
延长: “的Ext.data.Store” ,
模型: “AM.model.User”
数据: [
{ 名称: “爱德” , 电子邮件: “ed@sencha.com' },
{ 名称: “汤米,电子邮件: “tommy@sencha.com' }
]
});
我们重构将在下一节更容易,但应该不会影响应用程序的当前行为。如果现在我们刷新页面,双击就行,我们看到,“编辑用户”窗口仍然出现如预期。现在,它的时间来完成编辑功能:
模型中保存数据
现在,我们有我们的用户的电网负荷数据,当我们打开一个编辑窗口双击每一行,我们想保存更改用户。编辑用户窗口,上面定义包含一个表单(字段的名称和电子邮件),和一个保存按钮。首先,让我们更新我们的控制器的init函数,点击收听,保存按钮:
分机定义(的“AM.controller.Users' , {
INIT : 函数() {
。控制({
“视口>用户列表: {
itemdblclick 。editUser
}
“useredit按钮[动作=保存]' : {
点击: 这一点。updateUser
} } );
}
updateUser : 功能(按钮) {
控制台日志(“点击”保存“按钮” );
} } );
我们增加了一个的第二ComponentQuery选择到我们this.control
电话-这次useredit按钮行动=保存“
。这项工作作为第一选择同样的方式-使用useredit“
的xtype,我们上面定义集中在我们的编辑用户窗口,然后看起来与任何按钮“保存”
该窗口内的行动。当我们定义我们的编辑用户窗口,我们通过{行动:“保存”,
保存按钮,这给了我们一个简单的方法,针对该按钮。
我们能够满足自己的的updateUser
函数被调用,当我们点击“保存”按钮:
现在,我们已经看到了我们的处理程序已正确连接到“保存”按钮的Click事件,让填写真正逻辑updateUser
功能。在这个函数中,我们需要得到的数据的形式,更新我们的用户,然后保存返回到用户存储我们上面创建的。让我们看看我们如何可能做到这一点:
updateUser: function(button) {
var win = button.up('window'),
form = win.down('form'),
record = form.getRecord(),
values = form.getValues();
纪录。集(值);
胜利。关 闭();
}
让打破这里发生了什么事情。我们的click事件给了我们一个按钮,用户点击参考,但我们真正想要的是访问的形式,它包含的数据窗口本身。要得到的东西工作很快我们就使用ComponentQuery在这里再次,第一次使用button.up(“窗口”)
编辑用户窗口的引用,然后win.down(“形式”)
形式。
之后,我们只需获取当前加载到形式记录,它与任何形式输入用户更新。最后,我们关闭窗口,注意携带回给电网。这里就是我们看到,当我们再次运行我们的应用程序,更改名称字段'埃德斯宾塞',
并单击“保存”:
保存到服务器
很容易。让完成,它与我们的服务器端交互现在。目前,我们是硬编码到用户存储的两个用户记录,让我们开始阅读的AJAX的,而不是:
分机定义(的“AM.store.Users' , {
延长: “的Ext.data.Store” ,
模型: “AM.model.User” ,
自动加载: 真,
proxy: {
type: 'ajax',
url: 'data/users.json',
reader: {
type: 'json',
root: 'users',
successProperty: 'success'
}
}
});
在这里,我们删除“数据”
属性,并取代了它的代理。代理的方式来加载和保存数据从一家商店或一个模型,在Ext JS 4。有对AJAX,JSON - P和HTML5等等localStorage代理。在这里,我们使用一个简单的AJAX代理,告诉我们从URL加载数据的数据/ users.json“
。