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中是如何實現的。


一、校驗

對於最基本的校驗固然是不能缺乏的。這裏的校驗包括對空值、輸入字段的長度及是否正確都進行了校驗,
好比以下兩圖:




二、驗證碼刷新

如上圖中驗證碼爲 R8DR,點擊後變爲 0PSS
在後臺對驗證碼進行了大小寫處理,因爲大些更容易辨認,因此在前臺生成時用大些,輸入的驗證碼大小寫都是能夠的。



三、重置與肯定

點擊重置後會將輸入的內容清空



點擊肯定後則進入後臺頁面(目前仍是比較醜陋的),這裏利用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. }

javascript

剛開始學習的時候,螃蟹也是一頭霧水,可是因爲ExtJS5.0的書寫及其規範,API至關完整,因而,在學習的時候螃蟹儘可能的不脫離其設計思想,在原有的框架基礎上進行開發改進。

好比咱們定義一個類,就能夠經過如下的語法進行定義:

html

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



這樣,咱們就定義了一個TextClass的類,這個類裏有name和value兩個屬性,之後使用的時候,直接new或者Create就能夠了。

就比如上篇中咱們定義了登錄窗口,

java

  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一下就能夠了:

ajax

  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文件,經過本篇講解的類的定義規則,相信應該能夠看懂這種命名規範了。

下面咱們來看一下特殊的寫法:

json

  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
cookie

  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屬性,它的做用就是爲該類起一個別名,用過數據庫的朋友對此應該不陌生。

這樣再回頭看這兩行代碼應該知文識意了,沒錯,就是根據別名來引用的。

session

  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數據動態加載  
相關文章
相關標籤/搜索