extjs 5.0 mvvm模式

目录页 :《 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='#' οnclick='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


var store_itxxz = Ext.create('Ext.data.Store', {                   storeId:'simpsonsStore',                   fields:['empid''userName''sex'],                   proxy: {                       type: 'ajax',                       url: 'emp/queryAll',                       reader: {                           type: 'json',                           root: 'data'                       }                   },                   autoLoad: true               });  

然后就是如何调用的问题

var grid = Ext.create('Ext.grid.Panel', {                   title: 'Simpsons',                   store: store_itxxz,                   columns: [                       {header: '登录名',  dataIndex: 'userName'},                       {header: 'empid', dataIndex: 'empid', flex:1}                   ],                   dockedItems: [{                       xtype: 'pagingtoolbar',                       store: store_itxxz,   // GridPanel使用相同的数据源                       dock: 'bottom',                       displayInfo: true                   }]               });  

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

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

java后台代码:


/**   * 员工列表   * @return    * @throws Exception   */   @RequestMapping("/queryAll")   @ResponseBody   public Map<String,List<Employee>> queryAllEmps() throws Exception{       log.info("员工列表");       List<Employee> allList = employeeService.selectAllEmps();       Map<String,List<Employee>> map = new HashMap<String,List<Employee>>();       map.put("data", allList);       System.out.println(map);       return map;   }  

后台代码中返回的是一个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数据动态加载

 


 

 

转载于:https://my.oschina.net/u/1398304/blog/405725

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值