ExtJs4学习(十一)MVC应用模式
Extjs4 MVC有别于其他MVC架构,Extjs有他自己定义:
- Model是一个Field以及他的Data的集合,Modes知道如何通过Stores来表示数据,以能用于网格和其他组件。模型的工作很像Extjs3的记录集(Record class),通常通过数据加载器(Stores)渲染至网格(grid)和其他组件上边。
- View:用以装载任何类型的组件—grid、tree和panel等等。
- Controller—用来放使得app工作的代码,例如 render views , instantiating Models 或者其他应用逻辑。
本篇文章,我们将创建一个非常简单的应用程序,即用户数据管理,最后,你就会知道如何利用Extjs4 MVC去创建简单应用程序。Extjs4 MVC应用程序架构提供应用程序的结构性和一致性。这样的模式带来了一些重要的好处:
- 每个应用程序的工作方式相同,我们叧需要学习一次。
- 应用程序乀间的代码共享很容易,应为他们所有的工作方式都相同
- 你可以使用EXTJS提供的构建工具创建你应用程序的优化版本。
文件结构(File Structure):
<span style="font-family:Courier New;font-size:14px;"><html> <head> <title>Account Manager</title> <link rel="stylesheet" type="text/css" href="ext-4.0/resources/css/ext-all.css"> <script type="text/javascript" src="ext-4.0/ext-debug.js"></script> <script type="text/javascript" src="app.js"></script> </head> <body></body> </html></span>
创建app.js文件(Creating the application)
现在来创建一个简单的账户管理应用。首先,需要选择一个命名空间(所有extjs4应用应该使用一个单一的全局变来来作为命名空间)。暂时,使用“AM”来作为命名空间。
<span style="font-family:Courier New;font-size:14px;">Ext.application({ name : 'AM', appFolder : 'app', launch : function() { Ext.create('Ext.container.Viewport', { layout : 'fit', items : [ { xtype : 'panel', title : 'Users', html : 'List of users will go here' } ] }); } });</span>
以上代码,做了如下几件事。首先,调用Ext.application创建一个应用程序类的实例,设置了一个“AM”的命名空间,他将作为整个应用的全局变量,也将作为Ext.Loader的命名空间,然后通过appFolder来指定配置选顷设置相应的路径。最后,创建了一个简单的发射功能,这里仅仅创建了一个Viewport,其中包吨一个panel,使其充满整个窗口。
定义一个控制器(Defining a Controller)
<span style="font-family:Courier New;font-size:14px;">Ext.define('AM.controller.Users', { extend: 'Ext.app.Controller', init: function() { console.log('Initialized Users! This happens before the Application launch function is called'); } });</span>
<span style="font-family:Courier New;font-size:14px;">Ext.application({ ... controllers: [ 'Users' ], ... });</span>
<span style="font-family:Courier New;font-size:14px;">Ext.define('AM.controller.Users', { extend : 'Ext.app.Controller', init : function() { this.control({ 'viewport > panel' : { render : this.onPanelRendered } }); }, onPanelRendered : function() { console.log('The panel was rendered'); } });</span>在Users.js中,init凼数使用this.control来负责监听,由于使用了新的ComponentQuery引擎,所以可以快速方便的找到页面上组件的引用(viewport > panel),这有些类似CSS选择器,通过匹配,快速的找到相匹配的组件。
在上面的init凼数中,我们使用viewport > panel,来找到app.js中Viewport下的panel组件,然后,我们提供了一个对象的处理函数(this. onPanelRendered,注意,这里的对象是this,他的处理函数是onPanelRendered)。整个效果是,叧要符合触发render事件的任何组件,那举onPanelRendered函数将被调用。当运行我们的应用程序,我们将看到以下内容。
定义一个视图(Defining a View)
<span style="font-family:Courier New;font-size:14px;">Ext.define('AM.view.user.List', { extend : 'Ext.grid.Panel', alias : 'widget.userlist', title : 'All Users', initComponent : function() { this.store = { fields : [ 'name', 'email' ], data : [ { name : 'Ed', email : '[email protected]' }, { name : 'Tommy', email : '[email protected]' } ] }; this.columns = [ { header : 'Name', dataIndex : 'name', flex : 1 }, { header : 'Email', dataIndex : 'email', flex : 1 } ]; this.callParent(arguments); } });</span>
我们创建好的这个类,叧是一个非常普通的类,并没有任何意义,为了能让我们更好的使用这个定义好的类,所以我们使用alias来定义一个别名,这个时候,我们的类可以使用Ext.create()和Ext.widget()创建,在其他组件的子组件中,也可以使用xtype来创建。
<span style="font-family:Courier New;font-size:14px;">Ext.define('AM.controller.Users', { extend: 'Ext.app.Controller', views: [ 'user.List' ], init: ... onPanelRendered: ... });</span>
修改Users.js,增加views属性,修改app.js中的launch方法,将List渲染到Viewport。
<span style="font-family:Courier New;font-size:14px;">Ext.application({ ... launch: function() { Ext.create('Ext.container.Viewport', { layout: 'fit', items: { xtype: 'userlist' } }); } });</span>
控制网格(Controlling the grid)
<span style="font-family:Courier New;font-size:14px;">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('Double clicked on ' + record.get('name')); } });</span>
这里,我们修改了ComponentQuery的选择(‘userlist‘)和事件的名称(‘itemdblclick‘)和处理函数(‘editUser‘)。
<span style="font-family:Courier New;font-size:14px;">Ext.define('AM.view.user.Edit', { extend : 'Ext.window.Window', alias : 'widget.useredit', title : 'Edit User', 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); } });</span>
我们定义了一个子类,继承Ext.window.Window,然后使用initComponent创建了一个表单和两个按钮,表单中,两个字段分别装载用户名和电子邮件。接下来,我们修改视图控制器,使其可以载入用户数据。
<span style="font-family:Courier New;font-size:14px;">Ext.define('AM.controller.Users', { extend: 'Ext.app.Controller', views: [ 'user.List', 'user.Edit' ], init: ... editUser: function(grid, record) { var view = Ext.widget('useredit'); view.down('form').loadRecord(record); } });</span>
创建Model 和 Store
<span style="font-family:Courier New;font-size:14px;">Ext.define('AM.store.Users', { extend : 'Ext.data.Store', fields : [ 'name', 'email' ], data : [ { name : 'Ed', email : '[email protected]' }, { name : 'Tommy', email : '[email protected]' } ] });</span>
接下来修改两个文件:
<span style="font-family:Courier New;font-size:14px;">Ext.define('AM.controller.Users', { extend: 'Ext.app.Controller', stores: [ 'Users' ], ... });</span>
修改app/view/user/List.js,使其引用Users
<span style="font-family:Courier New;font-size:14px;">Ext.define('AM.view.user.List' ,{ extend: 'Ext.grid.Panel', alias : 'widget.userlist', //we no longer define the Users store in the `initComponent` method store: 'Users', ... });</span>
现在,我们定义的用户控制器已经能顺利的加载数据了,到目前,我们所定义的Store已经足够使用了,但是Extjs4提供了一个强大的Ext.data.Model类,不如,我们利用它来重构下我们Store,创建app/model/User.js
<span style="font-family:Courier New;font-size:14px;">Ext.define('AM.model.User', { extend : 'Ext.data.Model', fields : [ 'name', 'email' ] });</span>
创建好模型之后,我们将他引入用户控制:
<span style="font-family:Courier New;font-size:14px;">//the Users controller will make sure that the User model is included on the page and available to our app Ext.define('AM.controller.Users', { extend: 'Ext.app.Controller', stores: ['Users'], models: ['User'], ... }); // we now reference the Model instead of defining fields inline Ext.define('AM.store.Users', { extend: 'Ext.data.Store', model: 'AM.model.User', data: [ {name: 'Ed', email: '[email protected]'}, {name: 'Tommy', email: '[email protected]'} ] });</span>
完成上面的代码后,刷新页面,看到的结果和以前的一样。
通过model保存数据
<span style="font-family:Courier New;font-size:14px;">Ext.define('AM.controller.Users', { init : function() { this.control({ 'viewport > userlist' : { itemdblclick : this.editUser }, 'useredit button[action=save]' : { click : this.updateUser } }); }, updateUser : function(button) { console.log('clicked the Save button'); } });</span>
在this.control中,我们增加了一个选择项,‘useredit button[action=save]‘,当ComponentQuery找到符合的组件(button按钮,并且action动作为save),给他增加一个方法click,事件为updateUser。如图:
<span style="font-family:Courier New;font-size:14px;">updateUser:function(button) { var win = button.up('window'), form = win.down('form'), record = form.getRecord(), values = form.getValues(); record.set(values); win.close(); }</span>
这里,当我们点击Save按钮,我们将按钮本身传入函数updateUser,这时,我们使用button.up(‘window‘)来获取用户window的引用,然后使用win.down(‘form‘)来获取表单的引用,然后获取表单的记录,获取表单中的值,再设置记录为新的值,最后关闭window。
将数据保存到服务器
<span style="font-family:Courier New;font-size:14px;">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' } } });</span>
在AM.store.Users,移除data,用一个代理(proxy)取代它,用代理的方式来加载和保存数据。在Extjs4中,代理的方式有AJAX, JSON-P 和 HTML5 localStorage,这里使用AJAX代理。数据从data/users.json中得到。
<span style="font-family:Courier New;font-size:14px;">{ success:true, users:[ {id: 1, name: 'Ed', email: '[email protected]'}, {id: 2, name: 'Tommy', email: '[email protected]'} ] }</span>
到这里,唯一的变化是将Stroe的autoLoad设置为了true,这要求Stroe的代理要自动加载数据,当刷新页面,将得到和之前一样的效果。
最后一件事情,是将修改的数据发送到服务器,对于本例,服务端只用了一个静态的JSON,所以我们不会看到有任何变化,但至少可以确定这样做是可行的,相信服务端处理数据能力,大家都应该有。本例用,做个小小的变化,即新的代理中,使用api来更新一个新的URL。
<span style="font-family:Courier New;font-size:14px;">proxy: { type: 'ajax', api: { read: 'data/users.json', update: 'data/updateUsers.json' }, reader: { type: 'json', root: 'users', successProperty: 'success' } }</span>
<span style="font-family:Courier New;font-size:14px;">updateUser: function(button) { var win = button.up('window'), form = win.down('form'), record = form.getRecord(), values = form.getValues(); record.set(values); win.close(); this.getUsersStore().sync(); }</span>
现在,运行这个完整的例子,当双击grid中的某一样并进行编辑,点击Save按钮后,得到正确的请求和回应。
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。