EXT JS的MVC应用程序架构

在EXT的SDK中包含有一篇文章写的很好,可以作为广大初学EXT的ITer们的必读文章,因为全文都是英文,读起来非常不方便,所以在这里将该篇文章用本人的语言压缩成以下的博文:(仅供参考)

 原文地址请参考:https://github.com/sndpl/extjs4_mvc_skel 由4楼二胖提供,或者可以直接到ext官网下载SDK.

在MVC的布局模式中,所有的类都放置在app文件夹中,这个文件夹还包含了一些子文件夹用于命名你的models,views,controllers,stores.下图为simple这个应用程序的文件夹结构:

在ext-4.0文件夹中应包含必须文件:ext-debug.js和ext.js;

而我们的index.html中应include这两个文件,在index.html中,仅需要一下的代码:

View Code
 1 <html>
2 <head>
3 <title>Account Manager</title>
4
5 <link rel="stylesheet" type="text/css" href="ext-4.0/resources/css/ext-all.css">
6
7 <script type="text/javascript" src="ext-4.0/ext-debug.js"></script>
8
9 <script type="text/javascript" src="app.js"></script>
10 </head>
11 <body></body>
12 </html>

每一个ext js应用程序都由一个Application类作为开始,这个Application包含了全局设置,比如应用程序的名称,以及需要引用到的所有的models,views,controllers.这个Application同时也包含一个launch启动方法,这个方法会在所有的东西都准备好了以后自动运行。

在app.js中创建我们的应用程序

下面我们来创建一个简单的账户管理程序,这个程序会帮助我们管理我们的账户,首先我们需要一个全局的命名空间,我们的应用程序里面所用到所有类都会在这个命名空间里面。通常我们会选择一个简短的名字作为全局的命名空间:比如AM,来看一下我们的app.js中的代码:

View Code
 1 Ext.application({
2 name: 'AM',
3
4 appFolder: 'app',
5
6 launch: function() {
7 Ext.create('Ext.container.Viewport', {
8 layout: 'fit',
9 items: [
10 {
11 xtype: 'panel',
12 title: 'Users',
13 html : 'List of users will go here'
14 }
15 ]
16 });
17 }
18 });

首先,我们调用Ext.application去创建一个Application类,传递一个名字叫AM。这样它就能够自动的为我们创建一个全局的变量AM给我们,并将这个命名空间注册到Ext.Loader.代码中还创建了一个launch函数,这个函数里面创建了一个Viewport,它包含一个将会充满屏幕的panel.此时的效果如下图所示:

 

定义一个控制器
控制器是跟应用程序绑定在一起的,控制器所做的工作就是监听事件并作出相应,监听的事件通常是在views中,下面我们来创建一个控制器,在app/controller/下面新建一个User.js 里面代码如下:

View Code
1 Ext.define('AM.controller.Users', {
2 extend: 'Ext.app.Controller',
3
4 init: function() {
5 console.log('Initialized Users! This happens before the Application launch function is called');
6 }
7 });

因为我们创建了这个控制器,应用程序要与它关联的话就需要添加如下的代码:app.js改变如下:

View Code
1 Ext.application({
2 ...
3
4 controllers: [
5 'Users'
6 ],
7
8 ...
9 });

当我们的 应用程序加载进来的时候,这个Users控制器就会自动的加载进来,(因为我们把它声明在了application的定义上面),这个控制器的init方法会在应用程序的launch方法执行之间调用。在init方法里面就是我们的控制器如何与view进行交互的一些逻辑,具体看代码:

View Code
 1 Ext.define('AM.controller.Users', {
2 extend: 'Ext.app.Controller',
3
4 init: function() {
5 this.control({
6 'viewport > panel': { //这里是css选择器的形式
7 render: this.onPanelRendered //当页面进行渲染的时候就会促发该应用程序的onPanelRendered方法。
8 }
9 });
10 },
11
12 onPanelRendered: function() {
13 console.log('The panel was rendered');
14 }
15 });

我们重新刷新页面,可以看到如下效果:

定义一个视图

现在我们些的代码就只有两个js文件,app.js和User.js。接下来我们要继续组织一下我们的应用程序,开始用到views.

View无非就是一个组件,通常会定义为一个Ext js component的子类。下面我们要创建一个用户列表,可以新建一个List.js,位于app/view/user/下。List.js代码如下:

View Code
 1 Ext.define('AM.view.user.List' ,{
2 extend: 'Ext.grid.Panel',
3 alias : 'widget.userlist', //别名为userlist
4
5 title : 'All Users',
6
7 initComponent: function() { //初始化组件函数
8 this.store = {
9 fields: ['name', 'email'],
10 data : [
11 {name: 'Ed', email: 'ed@sencha.com'},
12 {name: 'Tommy', email: 'tommy@sencha.com'}
13 ]
14 };
15
16 this.columns = [
17 {header: 'Name', dataIndex: 'name', flex: 1},
18 {header: 'Email', dataIndex: 'email', flex: 1}
19 ];
20
21 this.callParent(arguments);
22 }
23 });

olumns(可以渲染的列)。接下来我们需要将这个view添加到我们的控制器中,因为我们使用了特殊的‘widget.'格式创建了一个这个视图的一个别名,所以我们可以使用userlist作为xtype,可以像通常使用Panel的形式一样来使用这个view.所以控制器的代码改变如下:

View Code
 1 Ext.define('AM.controller.Users', {
2 extend: 'Ext.app.Controller',
3
4 views: [
5 'user.List'
6 ],
7
8 init: ...
9
10 onPanelRendered: ...
11 });

在app.js中,launch方法内的代码就可以改变为如下了:(view替代原来的内容)

View Code
 1 Ext.application({
2 ...
3
4 launch: function() {
5 Ext.create('Ext.container.Viewport', {
6 layout: 'fit',
7 items: {
8 xtype: 'userlist'
9 }
10 });
11 }
12 });

下面是代码修改后的页面显示效果:

 

控制表格
注意到我们的onPanelRendered方法仍在调用,这是因为我们的表格仍然符合’viewport>panel‘选择器。其原因是我们的类继承了grid,归根结底是继承了Panel。

接下来我们再个表格添加双击的监听事件,以便于稍后的表格编辑。代码如下:

View Code
 1 Ext.define('AM.controller.Users', {
2 extend: 'Ext.app.Controller',
3
4 views: [
5 'user.List'
6 ],
7
8 init: function() {
9 this.control({
10 'userlist': {
11 itemdblclick: this.editUser
12 }
13 });
14 },
15
16 editUser: function(grid, record) {
17 console.log('Double clicked on ' + record.get('name'));
18 }
19 });

上面的代码写完后我们在表格中双击,控制台就会显示出相应的信息。在控制台中显示相应的信息自然很方便,不过我们现在要的是能够编辑表格,所以我们需要添加一个新的view.在app/view/user/目录下新建一个文件:Edit.js,里面代码如下:

View Code
 1 Ext.define('AM.view.user.Edit', {  //注意定义名称 的形式
2 extend: 'Ext.window.Window',
3 alias : 'widget.useredit',
4
5 title : 'Edit User',
6 layout: 'fit',
7 autoShow: true,
8
9 initComponent: function() {
10 this.items = [
11 {
12 xtype: 'form',
13 items: [
14 {
15 xtype: 'textfield',
16 name : 'name',
17 fieldLabel: 'Name'
18 },
19 {
20 xtype: 'textfield',
21 name : 'email',
22 fieldLabel: 'Email'
23 }
24 ]
25 }
26 ];
27
28 this.buttons = [
29 {
30 text: 'Save',
31 action: 'save'
32 },
33 {
34 text: 'Cancel',
35 scope: this,
36 handler: this.close
37 }
38 ];
39
40 this.callParent(arguments);
41 }
42 });

接下来就是如何将这个view关联到我们的应用程序中。在控制器中找到原来的editUser方法,将方法改为如下代码所示:

View Code
 1 Ext.define('AM.controller.Users', {
2 extend: 'Ext.app.Controller',
3
4 views: [
5 'user.List',
6 'user.Edit' //添加该view
7 ],
8
9 init: ...
10
11 editUser: function(grid, record) {
12 var view = Ext.widget('useredit'); //创建该view
13
14 view.down('form').loadRecord(record); //数据载入
15 }
16 });

代码中的down是EXT中的方法,能够往下查询到括号中对应的内容。保存代码,刷新页面,双击用户列表,页面显示如下:

创建model和store

现在我们有了编辑的表格,差不多可以开始对表格进行操作了,但在此之前我们还需要对代码进行一下重构。

在我们的AM.view.user.List这个view中,我们创建了一个store混合在代码中,这种方式也能让我们的应用程序工作的很好,但我们希望将它放在其他地方以便于在数据更新时得到方便.在这里我们主要把view中的代码拆开将store保存于另一个文件中,文件目录为:app/store/User.js;其代码具体为:

View Code
1 Ext.define('AM.store.Users', {
2 extend: 'Ext.data.Store',
3 fields: ['name', 'email'],
4 data: [
5 {name: 'Ed', email: 'ed@sencha.com'},
6 {name: 'Tommy', email: 'tommy@sencha.com'}
7 ]
8 });

我们需要做两个小的改动,一是在控制器中添加store的引用

View Code
1 Ext.define('AM.controller.Users', {
2 extend: 'Ext.app.Controller',
3 stores: [
4 'Users'
5 ],
6 ...
7 });

另一个改动是将去掉了store的view重新添加对他的引用

View Code
1 Ext.define('AM.view.user.List' ,{
2 extend: 'Ext.grid.Panel',
3 alias : 'widget.userlist',
4
5 //we no longer define the Users store in the `initComponent` method
6 store: 'Users',
7
8 ...
9 });

在上面的修改中,store里面还包含了fields字段,在EXT中,我们仍然可以将它分离出来,放在model中。新建User.js位于目录app/model/下。代码如下:

View Code
1 Ext.define('AM.model.User', {
2 extend: 'Ext.data.Model',
3 fields: ['name', 'email']
4 });

接下来我们就要更新一下我们的store便于与model的关联,同时也需要controller获取一个model的关联:

View Code
 1 //the Users controller will make sure that the User model is included on the page and available to our app
2 Ext.define('AM.controller.Users', {
3 extend: 'Ext.app.Controller',
4 stores: ['Users'],
5 models: ['User'],
6 ...
7 });
8
9 // we now reference the Model instead of defining fields inline
10 Ext.define('AM.store.Users', {
11 extend: 'Ext.data.Store',
12 model: 'AM.model.User',
13
14 data: [
15 {name: 'Ed', email: 'ed@sencha.com'},
16 {name: 'Tommy', email: 'tommy@sencha.com'}
17 ]
18 });

我们的代码重构会让我们在下一步更轻松,若我们重新刷新页面,并双击表格,页面仍能按照我们的语气弹出相应的窗口,现在是时候来完成表格的编辑方法了。

用模块保存数据

现在我们有了用户表格来加载数据,并在我们双击某一行的时候打开一个编辑窗口,我们可能会想保存经过修改的数据。首先我们来更新一下控制器的init方法里面的sava按钮单击事件。

View Code
 1 Ext.define('AM.controller.Users', {
2 init: function() {
3 this.control({
4 'viewport > userlist': {
5 itemdblclick: this.editUser
6 },
7 'useredit button[action=save]': {
8 click: this.updateUser
9 }
10 });
11 },
12
13 updateUser: function(button) {
14 console.log('clicked the Save button');
15 }
16 });

刷新页面,双击某行打开新窗口后,单击保存按钮后,控制台显示相应信息,说明代码正确执行了:


接下来我们再补充完整单击保存按钮的方法:

View Code
1 updateUser: function(button) {
2 var win = button.up('window'),
3 form = win.down('form'),
4 record = form.getRecord(),
5 values = form.getValues();
6
7 record.set(values);
8 win.close();
9 }

完成以上代码后,在单击保存按钮,页面的数据将会根据你的修改而显示出你修改的数据。

保存到服务器

整个应用程序很简单,接下来让我们将这个应用程序与服务器端进行一下交互。在store中把数据全部录在里面是一件很不爽的事情,因此我们可以将数据通过ajas读取出来。

store修改如下:

View Code
 1 Ext.define('AM.store.Users', {
2 extend: 'Ext.data.Store',
3 model: 'AM.model.User',
4 autoLoad: true,
5
6 proxy: {
7 type: 'ajax',
8 url: 'data/users.json',
9 reader: {
10 type: 'json',
11 root: 'users',
12 successProperty: 'success'
13 }
14 }
15 });

这里我们移除了data属性,并用proxy替代。proxies是在EXT JS4中从store或model加载或保存数据的一种方法。在这里我们的程序会被告知从url为data/users.json的路径中加载数据。

我们还添加了一个reader到代理上,这个reader能够响应出一种数据格式以使store能够读懂。在这里的意思即是使用json阅读器,并声明root和successProperty属性。最后我们创建一个json文件:data/users.json,并将之前的数据粘贴上去。

View Code
1 {
2 success: true,
3 users: [
4 {id: 1, name: 'Ed', email: 'ed@sencha.com'},
5 {id: 2, name: 'Tommy', email: 'tommy@sencha.com'}
6 ]
7 }

最后一件事我们要做的是发送动态修改信息到服务器。在这个例子中,我们使用静态的JSON文件在服务器端,因此我们不会看到任何数据库的改变但我们至少是可以知道整个应用程序是正常工作的。首先我们先对代理做出一点小小的改变,告诉他发送更新到一个不同的url上。

View Code
 1 proxy: {
2 type: 'ajax',
3 api: {
4 read: 'data/users.json',
5 update: 'data/updateUsers.json'
6 },
7 reader: {
8 type: 'json',
9 root: 'users',
10 successProperty: 'success'
11 }
12 }


我们仍然从users.json中读取数据,但任何更新都会发送到updateUsers.json上。这样我们就能够明确的知道所有的东西都在正常的工作中。这个updateUser.json文件包含{"success":true}.其他的改变我们要做的是告诉store在编辑完成后能够同步。在这里仅仅需要在udateUser方法中添加一行代码:

View Code
 1 updateUser: function(button) {
2 var win = button.up('window'),
3 form = win.down('form'),
4 record = form.getRecord(),
5 values = form.getValues();
6
7 record.set(values);
8 win.close();
9 this.getUsersStore().sync();
10 }

接下来就测试了!!!!!!












原文地址:https://www.cnblogs.com/moyiqing/p/2406366.html