Ext面向对象开发实践(turn)

示例程序简述:

这个Demo为了演示如将使用GridPanel显示数据,并为GridPanel添加工具条按钮,提供弹出式窗体新增数据。

使用到的Ext组件

这个Demo涉及到Ext中的GridPanel,FormPanel和Window三个组件。

效果图

现在开始讲解代码,首先看一下创建GridPanel的代码片段

  1. //定义数据列表面板类
  2. PersonListGridPanel = Ext.extend(Ext.grid.GridPanel, {
  3.     insertWin: null,
  4.     updateWin: null,
  5.     constructor: function() {
  6. //添加自定义事件
  7. this.addEvents("rowSelect");
  8. this.insertWin = new InsertPersonInfoWindow();
  9. this.insertWin.on("submit", this.onInsertWinSubmit, this);
  10. this.updateWin = new UpdatePersonInfoWindow();
  11. this.updateWin.on("submit", this.onUpdateWinSubmit, this);
  12.         PersonListGridPanel.superclass.constructor.call(this, {
  13.             renderTo: Ext.getBody(),
  14.             width: 360,
  15.             height: 300,
  16.             frame:true,
  17.             sm: new Ext.grid.RowSelectionModel({
  18.                 singleSelect:true,
  19.                 listeners: {
  20. "rowselect": {
  21.                         fn: function(sm, rowIndex, r) {
  22. this.fireEvent("rowSelect", r); //触发自定义事件
  23.                         },
  24.                         scope: this
  25.                     }
  26.                 }
  27.             }),
  28.             store: new Ext.data.JsonStore({
  29.                     data: [{name: "李宗盛", age: 28, sex: "男"}, {name: "林忆莲", age: 26, sex: "女"}],
  30.                     fields: ["name", "sex", "age"]
  31.             }),
  32.             draggable: false,
  33.             enableColumnMove: false,
  34.             title: "First Grid",
  35. //iconCls:'icon-grid',
  36.             colModel: new Ext.grid.ColumnModel([
  37.                 {header: "Staff Name", width: 100, menuDisabled: true},
  38.                 {header: "Age", width: 100, sortable: true, dataIndex: "age", align: "right", tooltip: "这里是提示信息"},
  39.                 {header: "Sex", width: 100, sortable: true, dataIndex: "sex", align: "center"}
  40.             ]),
  41.             tbar: [{
  42.                 text: "添加人员",
  43.                 handler: function() {
  44. //***************************************************
  45. //如果没有重写InsertPersonInfoWindow的Close方法
  46. //在调用之前需要检查其实例insertWin是否被释放
  47. //使用示例:
  48. //if (!this.insertWin) {
  49. //    this.insertWin = new InsertPersonInfoWindow();
  50. //}
  51. //this.insertWin.show();
  52. //***************************************************
  53. this.insertWin.show();
  54.                 },
  55.                 scope: this
  56.             }, "-", {
  57.                 text: "修改人员",
  58.                 handler: function() {
  59. var r = this.getActiveRecord();
  60. if (!r) return;
  61. //一定要先调用Show方法,而后再调用Load方法,
  62. //否则数据不会被呈现出来
  63. this.updateWin.show();
  64. this.updateWin.load(r);
  65.                 },
  66.                 scope: this
  67.             }, "-", {
  68.                 text: "删除人员",
  69.                 handler: function() {
  70. var r = this.getActiveRecord();
  71. if (!r) return;
  72.                     Ext.MessageBox.confirm("删除", "删除当前人员信息?", function(btn) { 
  73. if(btn == "yes") {
  74. this.delRecord(r);
  75.                         }
  76.                     }, this);
  77.                 },
  78.                 scope: this
  79.             }]
  80.         });
  81.     },
  82.     getActiveRecord: function() {
  83. var sm = this.getSelectionModel();
  84. //没有选中的记录时,是抛出异常还是返回null???????
  85. return (sm.getCount() === 0) ? null : sm.getSelected();
  86.     },
  87.     insert: function(r) {
  88. this.getStore().add(r);
  89.     },
  90.     delRecord: function(r) {
  91. this.getStore().remove(r);
  92.     },
  93.     onInsertWinSubmit: function(win, r) {
  94. this.insert(r);
  95.     },
  96.     onUpdateWinSubmit: function(win, r) {
  97.         alert('onUpdateWinSubmit');
  98.     }
  99. });

数据维护面板代码

  1. //定义数据维护面板,在后面定义的新增和修改窗体中都会使用到该面板
  2. PersonInfoFormPanel = Ext.extend(Ext.form.FormPanel, {
  3.     constructor: function() {
  4.         PersonInfoFormPanel.superclass.constructor.call(this, {
  5. //title: "Person Info",
  6.             frame: true,
  7.             width: 360,
  8.             labelWidth: 40,
  9.             defaultType: "textfield",
  10.             defaults: { anchor: "92%" },
  11.             items: [{
  12.                 name: "name", //注意,这里使用name属性而不是id,因为PersonInfoFormPanel会被添加和插入两个窗体使用,使用id会有冲突,导致组件不能被正确显示
  13.                 fieldLabel: "Name",
  14.                 allowBlank: false,
  15.                 emptyText: "请输入姓名",
  16.                 blankText: "姓名不能为空"
  17.             }, {
  18.                 name: "age",
  19.                 fieldLabel: "Age",
  20.                 vtype: "age"
  21.             }, {
  22.                 hiddenName: "sex",
  23.                 xtype: "combo",
  24.                 fieldLabel: "Sex",
  25.                 store: new Ext.data.SimpleStore({
  26.                     fields: [
  27.                        {name: 'Sex'}
  28.                     ],
  29.                     data:[["男"], ["女"]]
  30.                 }),
  31.                 mode: 'local',
  32.                 displayField:'Sex',
  33.                 triggerAction: 'all',
  34.                 emptyText:'选择性别...'
  35.             }]
  36.         })
  37.     },
  38.     getValues: function() {
  39. if (this.getForm().isValid()) {
  40. return new Ext.data.Record(this.getForm().getValues());
  41.         }
  42. else {
  43. throw Error("Error Message");
  44.         }
  45.     },
  46.     setValues: function(r) {
  47. this.getForm().loadRecord(r);
  48.     },
  49.     reset: function() {
  50. this.getForm().reset();
  51.     }
  52. });

对数据的维护有新增和更新两个动作,从设计的角度来讲就需要编写两个窗体对其进行操作。细心的朋友一定会想,新增和更新的动作都是针对相同的数据表,那么能不能只写一个窗体,然后复用呢?答案是肯定的。下面我们就先写一个窗体基类。

  1. //新增,修改窗体基类
  2. PersonInfoWindow = Ext.extend(Ext.Window, {
  3.     form: null,
  4.     constructor: function() {
  5. this.addEvents("submit");
  6. this.form = new PersonInfoFormPanel();
  7. //Ext.apply(this.form, {baseCls: "x-plain"});
  8.         PersonInfoWindow.superclass.constructor.call(this, {
  9.             plain: true,
  10.             width: 360,
  11.             modal: true, //模式窗体
  12.             onEsc: Ext.emptyFn,
  13.             closeAction: "hide",
  14.             items: [this.form],
  15.             buttons: [{
  16.                 text: "确  定",
  17.                 handler: this.onSubmitClick,
  18.                 scope: this
  19.             }, {
  20.                 text: "取  消",
  21.                 handler: this.onCancelClick,
  22.                 scope: this
  23.             }]
  24.         });
  25. //alert(this.onSubmitClick);
  26.     },
  27.     close: function() {
  28. //需要重写CLose方法,
  29. //否则在窗体被关闭其实体会被释放
  30. this.hide();
  31. this.form.reset();
  32.     },
  33.     onSubmitClick: function() {
  34. //alert(Ext.util.JSON.encode(this.form.getValues().data));
  35. try {
  36. this.fireEvent("submit", this, this.form.getValues());
  37. this.close();
  38.         }
  39. catch(_err) {
  40. return;
  41.         }
  42.     },
  43.     onCancelClick: function() {
  44. this.close();
  45.     }
  46. });

基类写了之后,我们就可以使用继承的方法来编写新进和更新窗体了。

  1. //定义新增数据窗体
  2. InsertPersonInfoWindow = Ext.extend(PersonInfoWindow, {
  3.     title: "添加"
  4. });
  5. //==============================================================================
  6. //定义编辑数据窗体
  7. UpdatePersonInfoWindow = Ext.extend(PersonInfoWindow, {
  8.     title: "修改",
  9.     load: function(r) {
  10. this.form.setValues(r);
  11.     }
  12. });

为了区分新增和更新窗体,我们在其各自的实现类中为其指定了Title属性,另外在更新窗体类中需要另外添加一个用于加载待编辑数据的方法Load。

脚本部分算是完成了,下面看看如何在HTML中使用。HTML中的引用代码

  1. <script type="text/javascript">
  2.             Ext.QuickTips.init();
  3. Ext.form.Field.prototype.msgTarget = "side";
  4. Ext.BLANK_IMAGE_URL = "http://localhost:8080/ext-2.2/resources/images/default/s.gif";
  5.             Ext.apply(Ext.form.VTypes, {
  6.                 "age": function(_v) {
  7.                     if (/^\d+$/.test(_v)) {
  8.                         var _age = parseInt(_v);
  9.                         if ((_age > 0) && (_age < 200)) return true;
  10.                     }
  11.                     return false;
  12.                 },
  13.                 "ageText": "年龄必须在0到200之间",
  14.                 "ageMask": /[0-9]/i
  15.             });
  16.             Ext.onReady(function() {
  17.                 new PersonListGridPanel();
  18.             });
  19. </script>

代码很简洁,也很清晰。只需要创建一个PersonListGridPanel即可,因为它自身包含了新增、修改的窗体对象,而新增和修改窗体中都使用到了负责数据编辑的PersonInfoFormPanel。

在PersonInfoFormPanel中使用了VTypes进行数据验证。

新增和修改窗体仅仅是界面,负责将用户在PersonInfoFormPanel中填写的数据传回到ListGrid中以便保存,或是将ListGrid中的数据传递到PersonInfoFormPanel中进行呈现,供用户编辑。

附上完整的HTML代码和JavaScript代码文件。

Grid.html

  1. <html>
  2. <head>
  3. <title>Ext Grid</title>
  4. <link rel="stylesheet" type="text/css" href="http://localhost:8080/ext-2.2/resources/css/ext-all.css"/>
  5. <script type="text/javascript" src="http://localhost:8080/ext-2.2/adapter/ext/ext-base.js"></script>
  6. <script type="text/javascript" src="http://localhost:8080/ext-2.2/ext-all.js"></script>
  7. <script type="text/javascript" src="PersonListGridPanel.js"></script>
  8. <script type="text/javascript">
  9.             Ext.QuickTips.init();
  10. Ext.form.Field.prototype.msgTarget = "side";
  11. Ext.BLANK_IMAGE_URL = "http://localhost:8080/ext-2.2/resources/images/default/s.gif";
  12.             Ext.apply(Ext.form.VTypes, {
  13.                 "age": function(_v) {
  14.                     if (/^\d+$/.test(_v)) {
  15.                         var _age = parseInt(_v);
  16.                         if ((_age > 0) && (_age < 200)) return true;
  17.                     }
  18.                     return false;
  19.                 },
  20.                 "ageText": "年龄必须在0到200之间",
  21.                 "ageMask": /[0-9]/i
  22.             });
  23.             Ext.onReady(function() {
  24.                 new PersonListGridPanel();
  25.             });
  26. </script>
  27. </head>
  28. <body>
  29. </body>
  30. </html>

PersonListGridPanel.js

  1. //定义数据列表面板类
  2. PersonListGridPanel = Ext.extend(Ext.grid.GridPanel, {
  3.     insertWin: null,
  4.     updateWin: null,
  5.     constructor: function() {
  6. //添加自定义事件
  7. this.addEvents("rowSelect");
  8. this.insertWin = new InsertPersonInfoWindow();
  9. this.insertWin.on("submit", this.onInsertWinSubmit, this);
  10. this.updateWin = new UpdatePersonInfoWindow();
  11. this.updateWin.on("submit", this.onUpdateWinSubmit, this);
  12.         PersonListGridPanel.superclass.constructor.call(this, {
  13.             renderTo: Ext.getBody(),
  14.             width: 360,
  15.             height: 300,
  16.             frame:true,
  17.             sm: new Ext.grid.RowSelectionModel({
  18.                 singleSelect:true,
  19.                 listeners: {
  20. "rowselect": {
  21.                         fn: function(sm, rowIndex, r) {
  22. this.fireEvent("rowSelect", r); //触发自定义事件
  23.                         },
  24.                         scope: this
  25.                     }
  26.                 }
  27.             }),
  28.             store: new Ext.data.JsonStore({
  29.                     data: [{name: "李宗盛", age: 28, sex: "男"}, {name: "林忆莲", age: 26, sex: "女"}],
  30.                     fields: ["name", "sex", "age"]
  31.             }),
  32.             draggable: false,
  33.             enableColumnMove: false,
  34.             title: "First Grid",
  35. //iconCls:'icon-grid',
  36.             colModel: new Ext.grid.ColumnModel([
  37.                 {header: "Staff Name", width: 100, menuDisabled: true},
  38.                 {header: "Age", width: 100, sortable: true, dataIndex: "age", align: "right", tooltip: "这里是提示信息"},
  39.                 {header: "Sex", width: 100, sortable: true, dataIndex: "sex", align: "center"}
  40.             ]),
  41.             tbar: [{
  42.                 name: "btnFirst",
  43. //text: "First",
  44.                 iconCls: "x-tbar-page-first",
  45.                 handler: function () {
  46. this.getSelectionModel().selectFirstRow();
  47.                 },
  48.                 scope: this
  49.             }, {
  50.                 name: "btnPrev",
  51. //text: "Prev",
  52.                 iconCls: "x-tbar-page-prev",
  53.                 handler: function () {
  54. this.getSelectionModel().selectPrevious();
  55.                 },
  56.                 scope: this
  57.             }, {
  58.                 name: "btnNext",
  59. //text: "Next",
  60.                 iconCls: "x-tbar-page-next",
  61.                 handler: function () {
  62. this.getSelectionModel().selectNext();
  63.                 },
  64.                 scope: this
  65.             }, {
  66.                 name: "btnLast",
  67. //text: "Last",
  68.                 iconCls: "x-tbar-page-last",
  69.                 handler: function () {
  70. this.getSelectionModel().selectLastRow();
  71.                 },
  72.                 scope: this
  73.             }, "-", {
  74.                 text: "添加",
  75.                 handler: function() {
  76. //***************************************************
  77. //如果没有重写InsertPersonInfoWindow的Close方法
  78. //在调用之前需要检查其实例insertWin是否被释放
  79. //使用示例:
  80. //if (!this.insertWin) {
  81. //    this.insertWin = new InsertPersonInfoWindow();
  82. //}
  83. //this.insertWin.show();
  84. //***************************************************
  85. this.insertWin.show();
  86.                 },
  87.                 scope: this
  88.             }, "-", {
  89.                 text: "修改",
  90.                 handler: function() {
  91. var r = this.getActiveRecord();
  92. if (!r) return;
  93. //如何将数据填充到窗体中?
  94. this.updateWin.show();
  95. this.updateWin.load(r);
  96.                 },
  97.                 scope: this
  98.             }, "-", {
  99.                 text: "删除",
  100.                 handler: function() {
  101. var r = this.getActiveRecord();
  102. if (!r) return;
  103.                     Ext.MessageBox.confirm("删除", "删除当前人员信息?", function(btn) { 
  104. if(btn == "yes") {
  105. this.delRecord(r);
  106.                         }
  107.                     }, this);
  108.                 },
  109.                 scope: this
  110.             }]
  111.         });
  112.     },
  113.     getActiveRecord: function() {
  114. var sm = this.getSelectionModel();
  115. //没有选中的记录时,是抛出异常还是返回null???????
  116. return (sm.getCount() === 0) ? null : sm.getSelected();
  117.     },
  118.     insert: function(r) {
  119. this.getStore().add(r);
  120.     },
  121.     delRecord: function(r) {
  122. this.getStore().remove(r);
  123.     },
  124.     onInsertWinSubmit: function(win, r) {
  125. this.insert(r);
  126.     },
  127.     onUpdateWinSubmit: function(win, r) {
  128.         alert('onUpdateWinSubmit');
  129.     }
  130. });
  131. //==============================================================================
  132. //定义数据维护面板,在后面定义的新增和修改窗体中都会使用到该面板
  133. PersonInfoFormPanel = Ext.extend(Ext.form.FormPanel, {
  134.     constructor: function() {
  135.         PersonInfoFormPanel.superclass.constructor.call(this, {
  136. //title: "Person Info",
  137.             frame: true,
  138.             width: 360,
  139.             labelWidth: 40,
  140.             defaultType: "textfield",
  141.             defaults: { anchor: "92%" },
  142.             items: [{
  143.                 name: "name", //注意,这里使用name属性而不是id,因为PersonInfoFormPanel会被添加和插入两个窗体使用,使用id会有冲突,导致组件不能被正确显示
  144.                 fieldLabel: "Name",
  145.                 allowBlank: false,
  146.                 emptyText: "请输入姓名",
  147.                 blankText: "姓名不能为空"
  148.             }, {
  149.                 name: "age",
  150.                 fieldLabel: "Age",
  151.                 vtype: "age"
  152.             }, {
  153.                 hiddenName: "sex",
  154.                 xtype: "combo",
  155.                 fieldLabel: "Sex",
  156.                 store: new Ext.data.SimpleStore({
  157.                     fields: [
  158.                        {name: 'Sex'}
  159.                     ],
  160.                     data:[["男"], ["女"]]
  161.                 }),
  162.                 mode: 'local',
  163.                 displayField:'Sex',
  164.                 triggerAction: 'all',
  165.                 emptyText:'选择性别...'
  166.             }]
  167.         })
  168.     },
  169.     getValues: function() {
  170. if (this.getForm().isValid()) {
  171. return new Ext.data.Record(this.getForm().getValues());
  172.         }
  173. else {
  174. throw Error("信息不完整");
  175.         }
  176.     },
  177.     setValues: function(r) {
  178. //alert(Ext.util.JSON.encode(r.data));
  179. this.getForm().loadRecord(r);
  180.     },
  181.     reset: function() {
  182. this.getForm().reset();
  183.     }
  184. });
  185. //==============================================================================
  186. //新增,修改窗体基类
  187. PersonInfoWindow = Ext.extend(Ext.Window, {
  188.     form: null,
  189.     constructor: function() {
  190. this.addEvents("submit");
  191. this.form = new PersonInfoFormPanel();
  192. //Ext.apply(this.form, {baseCls: "x-plain"});
  193.         PersonInfoWindow.superclass.constructor.call(this, {
  194.             plain: true,
  195.             width: 360,
  196.             modal: true, //模式窗体
  197.             onEsc: Ext.emptyFn,
  198.             closeAction: "hide",
  199.             items: [this.form],
  200.             buttons: [{
  201.                 text: "确  定",
  202.                 handler: this.onSubmitClick,
  203.                 scope: this
  204.             }, {
  205.                 text: "取  消",
  206.                 handler: this.onCancelClick,
  207.                 scope: this
  208.             }]
  209.         });
  210. //alert(this.onSubmitClick);
  211.     },
  212.     close: function() {
  213. //需要重写CLose方法,
  214. //否则在窗体被关闭其实体会被释放
  215. this.hide();
  216. this.form.reset();
  217.     },
  218.     onSubmitClick: function() {
  219. //alert(Ext.util.JSON.encode(this.form.getValues().data));
  220. try {
  221. this.fireEvent("submit", this, this.form.getValues());
  222. this.close();
  223.         }
  224. catch(_err) {
  225. return;
  226.         }
  227.     },
  228.     onCancelClick: function() {
  229. this.close();
  230.     }
  231. });
  232. //==============================================================================
  233. //定义新增数据窗体
  234. InsertPersonInfoWindow = Ext.extend(PersonInfoWindow, {
  235.     title: "添加"
  236. });
  237. //==============================================================================
  238. //定义编辑数据窗体
  239. UpdatePersonInfoWindow = Ext.extend(PersonInfoWindow, {
  240.     title: "修改",
  241.     load: function(r) {
  242. this.form.setValues(r);
  243.     }
  244. });
posted @ 2009-08-19 14:00  汉卿  Views(538)  Comments(0Edit  收藏  举报