移花接木 实例讲解Ext JS控件的扩展

发布时间 : 星期三 文章移花接木 实例讲解Ext JS控件的扩展更新完毕开始阅读

移花接木 实例讲解Ext JS控件的扩展

本文介绍了Ext的基本概念以及扩展Ext的一般方法,通过三个应用场景,详细描述了如何从已有的Ext控件出发,借鉴其他控件的功能,开发出满足实际需要的新控件。本文的目的,旨在抛砖引玉,希望能给初学Ext的同仁们一点启发和参考,开发出更多、功能更强大的组件。

Ext JS是一种强大的JavaScript库,可以用来开发RIA(Rich Internet Applications),也即富客户端的Ajax应用,是一个与后台技术无关的前端Ajax框架。 Ext JS最开始基于YUI(Yahoo!UserInterfaceLibrary)技术,由开发人员JackSlocum开发,通过参考JavaSwing等机制来组织可视化组件,无论从UI界面上CSS样式的应用,到数据解析上的异常处理,都可算是一个非常优秀的Web开发框架。

对于大多数程序员来说,我们没有任何美术功底,公司的很多项目也没有配备美工,要想开发吸引人眼球的用户界面,一直以来不是一件容易的事情。但是Ext的出现使得开发美观的界面变得容易,Ext提供了表格、树、布局、按钮等很多外观绚丽、功能强大的控件,为我们的日常开发工作节约了大量的时间和精力。更重要的是这个框架是完全面向对象且可扩展的,通过对现有的库的功能进行修改或加入新的功能,来实现Ext框架中没有的功能。

扩展Ext组件

扩展(extension)在Ext中就是指衍生的子类。假设我们已经有一个附有一些方法的基类,现在欲加入新方法。我们可以利用框架的继承特性和JavaScript创建新类的语言特性组合新的一个类。

Ext提供了这样的一个实用函数Ext.extend在Ext框架中实现类继承的机制。这赋予了扩展任何JavaScript基类的能力,而无须对类自身进行代码的修改,扩展Ext组件这是个较理想的方法。

要从一个现有的类创建出一个新类,首先要通过一个函数声明新类的构造器,然后调用新类属性所共享的扩展方法。这些共享的属性通常是方法,但是如果要在实例之间共享数据,应该也一同声明。

JavaScript并没有提供一个自动的调用父类构造器的机制,所以必须通过属性superclass在构造器中显式调用父类。第一个参数总是this,以保证构造器工作在调用函数的作用域。

1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14.

清单1.扩展Ext组件的基本方法

MyNewClass=function(arg1,arg2,etc){ //显式调用父类的构造函数

MyNewClass.superclass.constructor.call(this,arg1,arg2,etc); };

Ext.extend(MyNewClass,SomeBaseClass,{ myNewFn1:function(){ //etc. },

myNewFn2:function(){ //etc. } });

使用时,我们需要实例化对象:

15. 16. 17.

清单2.实例化新的组件对象

varmyObject=newMyNewClass(arg1,arg2,etc);

掌握了扩展Ext组件的基本方法之后,我们就可以随意构造满足特定需求的组件。然而Ext里已有的组件和示例永远是我们取之不尽,用之不竭的创造源泉。本文以三个Ext组件为基础,“嫁接”了其他组件的功能,形成三个新的组件,实现了现有Ext组件没有的功能。本文的目的,旨在抛砖引玉,希望能给初学Ext的同仁们一点启发和参考,开发出更多、功能更强大的组件。

移Property Grid之花接EditorGrid之木

首先,介绍一下我们的场景和实际需求。某大学要建设一个教职工科研基金的管理系统,该系统可供基金设置人员设置基金申请条件、发放步骤等,申请人员填报申请人信息、申领基金等。这里以构建一个基金申请条件的组件为例。条件制定人员在制定申请条件时,可以随意添加、删除申请条件;对于某些申请条件,比如院系、性别等要求系统能提供预先定义好的选项供条件制定人员选择,而对于比如特长、年龄等内容不明确的或者选项过多无法列举的情况,则直接提供输入框供条件制定人员输入。

为了用Ext构建这样的组件,我们首先想到的是选用EditorGrid组件或者Property Grid组件。EditorGrid(可编辑表格控件)扩展自GridPanel,提供对于选中列的单元格编辑。可编辑的列是通过在表示表格的列信息的类Ext.grid.ColumnModel中添加editor来实现的。但是这个editor是对整个列有效的,就是说每一行在该列的位置的数据的编辑器是一样的。

Property Grid(属性表格)扩展自EditorGridPanel,所以可以直接编辑右边属性值部分的内容。但是,只是右边的,即使你单击左边的单元格,编辑器也只会出现在右边。实际上,我们可以用散列表来形容Property Grid,左边可以看作key,右边的是value。key是由我们指定好的,用户只需要修改对应的value即可。

Property Grid默认的编辑器包括TextField、DateField、NumberField和ComboBox,也就只能处理数字、字符串的输入和日期的选择,布尔值的选择等一般的情况。当我们想对编辑器进行更详细的配置时,就需要用到Property Grid的customEditors,为指定id的那行数据设置对应的编辑器。customEditors和source的设置基本一样,只需要将两者的属性名称对应起来,并且为customEditors里的所有属性指定一个editor。

Property Grid虽然能够给不同的单元格定制不同的编辑器,但是一方面这种表格只有两列,第一列还不可编辑,而且表格的内容(source)需要事先确定;另一方面定义customEditors的时候必须知道表格的内容(source),而且必须将两者的属性名称对应起来。EditorGrid其实已经大部分满足了我们的需求,只是不能对每个单元格定制编辑器,只能指定列编辑器。

经过上面的分析,单纯的使用任何一个控件,都难以达到我们的目的。同时我们发现问题主要出在EditorGrid的列模式(ColumnModel)上,Property Grid就是扩展自EditorGrid,通过对其ColumnModel的扩展来支持单元格的编辑器。所以我们尝试把EditorGrid的ColumnModel扩展一下,使得新的ColumnModel支持customEditors,这样我们就获得了对编辑器的完全控制权,可以根据表格的内容动态的改变单元格的编辑器了。清单3是我们为满足上述需求而扩展的新类MyColumnModel的部分代码,清单4是使用MyColumnModel构造了一个EditorGrid作为基金申请条件组件。

1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22.

清单3.定义新类MyColumnModel

Ext.ns('Ext.ux.grid'); //新类MyColumnModel的构造函数

Ext.ux.grid.MyColumnModel=function(grid,store,column){ this.grid=grid; this.store=store;

vargender=[ ['0100','男'], ['0101','女'] ];

vardepartment=[ ['0200','文学院'], //省略部分代码 ['0207','医学部'] ];

vartitle=[ ['0300','助教'], //省略部分代码 ['0303','教授'] ];

23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53. 54. 55. 56. 57. 58. 59. 60. 61. 62. 63. 64. 65. 66. 67.

vargenderCombo=newExt.form.ComboBox({ store:newExt.data.SimpleStore({ fields:['value','text'], data:gender }),

emptyText:'请输入', mode:'local',

triggerAction:'all', valueField:'value', displayField:'text', readOnly:true });

vardepartmentCombo=newExt.form.ComboBox({ store:newExt.data.SimpleStore({ fields:['value','text'], data:department }),

//与上面定义genderCombo类似,故省略部分代码 … });

vartitleCombo=newExt.form.ComboBox({ store:newExt.data.SimpleStore({ fields:['value','text'], data:title }),

//与上面定义genderCombo类似,故省略部分代码 … });

//当选择“性别”、“院系”、“职称”时,提供相应的下拉列表作为单元格编辑器, 供用户选择;当选择“年龄”、“论文数量”时,提供数字文本框供用户输入 this.customEditors={

'GENDER':newExt.grid.GridEditor(genderCombo),

'DEPARTMENT':newExt.grid.GridEditor(departmentCombo), 'TITLE':newExt.grid.GridEditor(titleCombo),

'AGE':newExt.grid.GridEditor(newExt.form.NumberField({selectOnFocus:true, style:'text-align:left;'})),

'PAPER':newExt.grid.GridEditor(newExt.form.NumberField({selectOnFocus:true, style:'text-align:left;'})) };

Ext.ux.grid.MyColumnModel.superclass.constructor.call(this,column); };

Ext.extend(Ext.ux.grid.MyColumnModel,Ext.grid.ColumnModel,{ //通过覆盖父类中的方法getCellEditor,实现根据表达式中条件列的不同取值, 为表达式的值所在单元格返回不同的编辑器

getCellEditor:function(colIndex,rowIndex){

68. 69. 70. 71. 72. 73. 74. 75. 76. 77. 78. 79. 80. 81. 82. 83. 84. 85. 86. 87.

varp=this.store.getAt(rowIndex);

n=p.data.attrName;//对应表达式的条件列的取值

if(colIndex==4)//表达式的值propertyValue所在的列 {

if(this.customEditors[n]){ returnthis.customEditors[n]; }else{

//如果没有定义特定的单元格编辑器,则返回普通的文本框编辑器 vared=newExt.grid.GridEditor(newExt.form.TextField({ selectOnFocus:true }) );

returned; } } else

returnthis.config[colIndex].editor; } });

1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22.

清单4.基金申请条件组件

Ext.onReady(function(){ varcomboData1=[ ['AGE','年龄'], //省略部分代码

['DEPARTMENT','院系'] ];

varcomboData2=[ ['>','大于'], //省略部分代码 ['!=','不等于'] ];

varcombo1=newExt.form.ComboBox({ id:'attrCombo',

store:newExt.data.SimpleStore({ fields:['value','text'], data:comboData1 }),

emptyText:'请选择', mode:'local',

triggerAction:'all',

联系合同范文客服:xxxxx#qq.com(#替换为@)