文档章节

extjs 5.0 mvvm模式

村长大神
 村长大神
发布于 2015/04/24 01:20
字数 2386
阅读 114
收藏 5
目录页 :《 extjs5.0学习笔记

Ext JS提供了mvc和mvvm的应用程序框架支持,这两种架构方法都是关注于将应用程序代码和业务逻辑分离。每一种方法都有自己的优点,这取决于怎么分离应用程序模块。下面我们就简单看一下:

什么是MVC框架?
在一个MVC框架中,大多数的类要么是模型(model)要么是视图(view)要么是控制器(controller)。用户(user)与视图(view)交互,视图(view)呢又显示模型(model)中的数据(data)。这些交互都被控制器(controller)监控,控制器(controller)又在需要的时候通过更新模型(model)和视图(view)与响应交互。


什么是mvvm框架?

mvvm简单说来就是在MVC的基础上,新增了一个类似数据仓库的概念。就是说我有了数据模型(model),也有了视图展现(view),还有对其分发处理的控制器(controller)之后,多了一个储蓄所,如下图:



上面的三个模块就是传统的MVC模式,ExtJS在此基础上提供了VM模块。它发出请求,通过我们指定的模型来组装后返回,之后每次有数据请求时,都可以从这里获取数据,减少了服务器的请求次数。

层级结构关系

下面是ExtJS的MVVM框架的目录结构,对于不知道Extjs环境如何部署的朋友,可参考这篇文章《
Extjs5.0集成Eclipse 》。



这里能够很清楚的看到controller、model、store及view三个层次,也就是MVVM的分层目录。这种思想在ExtJS4.X中也有体现,但是在5.X之后添加了新的特性,就是viewmodel和viewcontroller:





这里的viewmodel就是MVVM中的VM,viewcontroller就是在原来controller基础上的演进,目的是实现了动态加载,防止一次性加载过多的js导致的数据阻塞的问题。





上图就展现了login文件夹下三个js文件的关系。Login.js是一个登陆窗体,调用的方法逻辑都在LoginController.js中,项目初始化的参数存储在LoginModel.js,各司其职,非常明了。

下篇就以一个登录的实例来介绍下ExtJS5.0中是如何实现的。


1、校验

对于最基本的校验当然是不能缺少的。这里的校验包括对空值、输入字段的长度及是否正确都进行了校验,
比如如下两图:




2、验证码刷新

如上图中验证码为 R8DR,点击后变为 0PSS
在后台对验证码进行了大小写处理,由于大些更容易辨认,所以在前台生成时用大些,输入的验证码大小写都是可以的。



3、重置与确定

点击重置后会将输入的内容清空



点击确定后则进入后台页面(目前还是比较丑陋的),这里利用session进行了限制,如果正常登陆后刷新页面是不会重新登陆的。




下一篇螃蟹就登陆的ExtJS代码进行详解,核心代码如下:



  1. Ext.define('app.view.login.Login', {
  2. extend: 'Ext.window.Window',
  3. requires: [
  4. 'app.view.login.LoginController',
  5. 'app.view.login.LoginModel',
  6. 'Ext.form.Panel',
  7. 'Ext.button.Button',
  8. 'Ext.form.field.Text',
  9. 'Ext.form.field.ComboBox'
  10. ],
  11. viewModel: 'login',
  12. controller: 'login',
  13. title: 'IT学习者-人事管理系统登陆',
  14. closable: false,
  15. width : 400,
  16. height : 230,
  17. cls: 'login',
  18. buttonAlign : 'center',
  19. items:[{
  20. xtype : "displayfield",
  21. value : "",
  22. height:30,
  23. margin : "0 0 0 0"
  24. },{
  25. layout : "column",
  26. items : [{
  27. columnWidth:.7,
  28. xtype: 'form',
  29. reference: 'form',
  30. defaults : {
  31. labelSeparator : ':',
  32. labelWidth : 60,
  33. width : 200,
  34. labelAlign : 'left'
  35. },
  36. defaultType : 'textfield',
  37. items : [ {
  38. xtype : 'textfield',
  39. fieldLabel : ' 用户名 ',
  40. emptyText:"请输入用户名",
  41. regex : /([A-Za-z]{1})\w{1,19}/,
  42. regexText : '用户名格式有误',
  43. name : 'loginName',
  44. allowBlank : false,
  45. blankText : '用户名不能为空',
  46. minLength : 5,
  47. minLengthText : '用户名的长度为[5-16]',
  48. maxLength : 16,
  49. maxLengthText : '用户名的长度为[5-16]',
  50. margin : "10 10 10 50"
  51. }, {
  52. xtype : 'textfield',
  53. name : 'password',
  54. inputType : 'password',
  55. fieldLabel : '密 码',
  56. fieldCls : 'password',
  57. emptyText:"请输入密码",
  58. inputType : 'password',
  59. allowBlank:false,
  60. blankText : '密码不能为空',
  61. minLength : 5,
  62. minLengthText : '密码的长度为[5-20]',
  63. maxLength : 20,
  64. maxLengthText : '密码的长度为[5-20]',
  65. margin : "15 10 10 50"
  66. },{
  67. xtype:'textfield',
  68. width:120,
  69. fieldLabel : '验证码',
  70. name : 'authcode',
  71. allowBlank:false,
  72. blankText : '验证码不能为空',
  73. margin : "15 0 0 50"
  74. },{
  75. xtype:'panel',
  76. columnWidth:.4,
  77. height:30,
  78. html:"<a href='#' onclick='javascript:refreshCode();'><img id='validateCodeImg' title='点击更换' alt='点击更换' src='authCode' /></a>",
  79. margin : "-26 0 175"
  80. }]
  81. },{
  82. layout:'fit',
  83. bodyStyle: 'background:transparent',//设置为透明,不不妨碍更换主题了
  84. columnWidth:.28,
  85. height:120,
  86. items:[{
  87. xtype : "displayfield",
  88. hideLabel : true,
  89. margin : "-105 0 0 0",
  90. value : "<img src='./images/itxxz.png' />"
  91. }]
  92. }]
  93. }],
  94. buttons: [{
  95. text: '确定',
  96. listeners: {
  97. click: 'onLoginClick'
  98. }
  99. },{
  100. text: "重置",
  101. handler: function () {
  102. this.up('window').down('form').getForm().reset();
  103. }
  104. }]
  105. });
  106. //刷新验证码
  107. function refreshCode() {
  108. document.getElementById("validateCodeImg").src = "authCode?"+Math.random();
  109. }

刚开始学习的时候,螃蟹也是一头雾水,但是由于ExtJS5.0的书写及其规范,API相当完整,于是,在学习的时候螃蟹尽量的不脱离其设计思想,在原有的框架基础上进行开发改进。

比如我们定义一个类,就可以通过以下的语法进行定义:

  1. Ext.define('TextClass', {
  2. name: 'itxxz',
  3. value: 'IT学习者'
  4. });



这样,我们就定义了一个TextClass的类,这个类里有name和value两个属性,以后使用的时候,直接new或者Create就可以了。

就好比上篇中我们定义了登陆窗口,

  1. Ext.define('app.view.login.Login', {..}



这里的定义就与TextClass的定义不同了,学过java的朋友可能更好理解一些,这里的 app.view.login.Login 其实就是一个文件的路径,而app并非如下图的根路径,而是我们定义的命名空间,具体的定义规则在《Extjs5.0集成Eclipse》中的sencha命令已有介绍。

那么
view.login.Login就是文件的路径了,比如我们的登陆窗口是定义的Login.js文件,那么定义这个类的时候,规则就是命名空间加上路径最后以类的名字结尾,这样就可以找到该文件了,就好比我们定义app.view.login.Login一样,如下图:





这时候问题就来了,如果我们想定义一个window窗口,该如何下手?

在ExtJS中也引入了集成的思想,这样就避免了我们重复发明轮子的烦恼,想实现什么,只要extend一下就可以了:

  1. extend: 'Ext.window.Window',



在我们平常写js的时候往往会有很多js的引入来相互配合,这在ExtJS中也有体现,就是通过require来实现:

  1. requires: [
  2. 'app.view.login.LoginController',
  3. 'app.view.login.LoginModel',
  4. 'Ext.form.Panel',
  5. 'Ext.button.Button',
  6. 'Ext.form.field.Text',
  7. 'Ext.form.field.ComboBox'
  8. ],


这是我们需要的js文件,通过本篇讲解的类的定义规则,相信应该可以看懂这种命名规范了。

下面我们来看一下特殊的写法:

  1. viewModel: 'login',
  2. controller: 'login',


这里是引用viewModel和controller,有关这方面的介绍可看一下《ExtJS5.0的mvvm分层思想》。

通过上图中可以看到,login文件夹下一共定义了三个文件:Login.js、LoginController.js、LoginModel.js 。

Login.js的代码在上一篇已经张贴了出来,下面先简单看下另外的代码:

LoginController.js

  1. Ext.define('app.view.login.LoginController', {
  2. extend: 'Ext.app.ViewController',
  3. alias: 'controller.login',
  4. loginText: 'Logging in...',
  5. constructor: function () {
  6. this.callParent(arguments);
  7. this.loginManager = new app.LoginManager({});
  8. },
  9. onSpecialKey: function(field, e) {
  10. if (e.getKey() === e.ENTER) {
  11. this.doLogin();
  12. }
  13. },
  14. onLoginClick: function() {
  15. this.doLogin();
  16. },
  17. doLogin: function() {
  18. var form = this.lookupReference('form');
  19. if (form.isValid()) {
  20. Ext.getBody().mask(this.loginText);
  21. this.loginManager.login({
  22. data: form.getValues(),
  23. scope: this,
  24. success: 'onLoginSuccess',
  25. failure: 'onLoginFailure'
  26. });
  27. }
  28. },
  29. onLoginFailure: function() {
  30. Ext.getBody().unmask();
  31. },
  32. onLoginSuccess: function() {
  33. Ext.getBody().unmask();
  34. this.fireViewEvent('login', this.getView(), null, null, this.loginManager);
  35. }
  36. });


LoginModel.js

  1. Ext.define('app.view.login.LoginModel', {
  2. extend: 'Ext.app.ViewModel',
  3. alias: 'viewmodel.login',
  4. // Just some data to seed the process. This might be pulled from a cookie or other
  5. // in a real app.
  6. data: {
  7. defaultOrg: 1,
  8. username: 'IT学习者-螃蟹'
  9. }
  10. });


在上面两贴代码的第三行,都有一个alias属性,它的作用就是为该类起一个别名,用过数据库的朋友对此应该不陌生。

这样再回头看这两行代码应该知文识意了,没错,就是根据别名来引用的。

  1. viewModel: 'login',
  2. controller: 'login',


在这样引用后,ExtJS会默认生成这两个文件的对象了。

这篇就先介绍类的定义继承及引用,下篇我们继续分析

 

在前几篇的教程中,螃蟹已经简单介绍了Extjs如何加载java后台的数据,不过是以项目中所定义的规范加载的,鉴于不少朋友依旧咨询这方面的问题,这里就以store为例,单独说明一下

这是用于加载数据的请求,有些类似ajax,指定请求的url,请求的字段属性,也就是fields中定义的属性,再一个就是要指定根节点root


  1. var store_itxxz = Ext.create('Ext.data.Store', {  
  2.                 storeId:'simpsonsStore',  
  3.                 fields:['empid''userName''sex'],  
  4.                 proxy: {  
  5.                     type: 'ajax',  
  6.                     url: 'emp/queryAll',  
  7.                     reader: {  
  8.                         type: 'json',  
  9.                         root: 'data'  
  10.                     }  
  11.                 },  
  12.                 autoLoad: true  
  13.             });  


然后就是如何调用的问题

  1. var grid = Ext.create('Ext.grid.Panel', {  
  2.                 title: 'Simpsons',  
  3.                 store: store_itxxz,  
  4.                 columns: [  
  5.                     {header: '登录名',  dataIndex: 'userName'},  
  6.                     {header: 'empid', dataIndex: 'empid', flex:1}  
  7.                 ],  
  8.                 dockedItems: [{  
  9.                     xtype: 'pagingtoolbar',  
  10.                     store: store_itxxz,   // GridPanel使用相同的数据源  
  11.                     dock: 'bottom',  
  12.                     displayInfo: true  
  13.                 }]  
  14.             });  


这里第3行和第10行的store:store_itxxz中,左边的store是指grid中定义的数据源属性,右边的store_itxxz是指我们数据对象。

第10行是用来加载列表的数据,做显示用,第10行为分页用。

java后台代码:


  1. /** 
  2.  * 员工列表 
  3.  * @return  
  4.  * @throws Exception 
  5.  */  
  6. @RequestMapping("/queryAll")  
  7. @ResponseBody  
  8. public Map<String,List<Employee>> queryAllEmps() throws Exception{  
  9.     log.info("员工列表");  
  10.     List<Employee> allList = employeeService.selectAllEmps();  
  11.     Map<String,List<Employee>> map = new HashMap<String,List<Employee>>();  
  12.     map.put("data", allList);  
  13.     System.out.println(map);  
  14.     return map;  
  15. }  


后台代码中返回的是一个map,以ajax形式返回,是SpringMVC的基本用法,这里就不多介绍了。

第12行,map中put了一个key为data,value为allList的元素,这里的data就是store_itxxz中的root指定的根节点。

也可以修改一下,比如根节点叫做itxxz_data,那么再此处只需要将key改为itxxz_data,store_itxxz中奖root的定义data也改为itxxz_data就可以了。

数据的返回格式如下:


{ data: [ {empid: '001', userName:'IT学习者', sex:'男'}, {empid: '002', userNmae:'螃蟹', sex:'女'}  ] }


效果图可参考《Extjs5.0 GridPanel数据动态加载

 


 

 

本文转载自:http://www.itxxz.com/a/gaoji/2015/0119/556.html

共有 人打赏支持
上一篇: MySQL之连接
下一篇: jquery遍历table
村长大神
粉丝 163
博文 876
码字总数 904789
作品 0
杭州
程序员
私信 提问
Extjs MVC开发模式详解

在JS的开发过程中,大规模的JS脚本难以组织和维护,这一直是困扰前端开发人员的头等问题。Extjs为了解决这种问题,在Extjs 4.x版本中引入了MVC开发模式,开始将一个JS(Extjs)应用程序分割成...

鱼煎
2017/11/02
0
0
ExtJs4.1目录结构介绍和使用说明

一、在做ExtJs开发之前首先要到网站上下载ExtJs的开发包,我用的最新版本是4.1.1。此版本相对于之前的版本目录结构发生了一些变化,没有了adapter目录, 目录结构如下 文件/文件夹名的作用:...

Junn
2013/01/17
0
1
ExtJS开发环境的搭建,spket工具安装详解

集成:ExtJS,MyEcplise和Spket。 前提:安装好的myecplise(我用的是MyEcplise10) 步骤: 先安装Spket 1 下载Spket的jar文件,spket-1.6.18.jar 2 将jar文件解压到MyEcplise的dropins文件夹...

day戴
2014/09/04
0
0
Eclipse开发Javascript环境配置(含EXTJs配置) 转载

有三种Javascript编辑器可供选择: 1. JSDT 2. JSEclipse 3. Spket 分别介绍这三种插件的安装: 1. JSDT 是WPT自带的插件 只要装了WTP就不用单独安装JSDT了。也可以从这里了解JSDT的一些信息...

晨曦之光
2012/03/24
0
0
Extjs GridPanel用法详解

创建GridPanel 要使用GridPanel,首先要定义Store,而在创建Store的时候必须要有Model,因此我们首先来定义Model: //1.定义ModelExt.define("MyApp.model.User", { }); 然后创建Store: //...

鱼煎
2017/11/02
0
0

没有更多内容

加载失败,请刷新页面

加载更多

降压变换器 Buck

特点 输入输出极性相同。 工作过程 在 MOS 导通时,输入电源通过 L 和 C 滤波后向负载端提供电流;当 MOS 断开后,L 通过二极管续流,保持负载电流连续。输出电压因为占空比的作用,不会超过...

colinux
今天
1
0
Apache日志不记录访问静态文件,访问日志切割,静态元素过期时间设置

Apache配置不记录访问静态文件的日志 网站大多元素为静态文件,如图片、css、js等,这些元素可以不用记录 vhost原始配置 <VirtualHost *:80> ServerAdmin test@163.com DocumentRoo...

野雪球
今天
3
0
聊聊storm的ICommitterTridentSpout

序 本文主要研究一下storm的ICommitterTridentSpout ICommitterTridentSpout storm-core-1.2.2-sources.jar!/org/apache/storm/trident/spout/ICommitterTridentSpout.java public interface......

go4it
今天
4
0
Ubuntu常用操作

查看端口号 netstat -anp |grep 端口号 查看已使用端口情况 netstat -nultp(此处不用加端口号) netstat -anp |grep 82查看82端口的使用情况 查找被占用的端口: netstat -tln netstat -tl...

hc321
昨天
3
0
网站cdn的静态资源突然访问变的缓慢,问题排查流程

1.首先我查看了一下是否自己的网络问题,通过对比其他资源的访问速度和下载速度,确认不是 2.通过ping 和 tracert 判断cdn域名能否正常访问,(最后回想感觉这一步可以省略,因为每次最终能访...

小海bug
昨天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部