8
回答
EZo = 易组 : 开发ExtJS接口风格的新利器
华为云实践训练营,热门技术免费实践!>>>   

前言

AJAX的解决方案非常多,其中ExtJS以具备丰富的组件与详细说明文件而著名,也深受企业用户与广大开发者喜爱。

笔者多年前在参与某个项目时,因为要提升网页的美观与易用性,在评估解决方案时,ExtJS让笔者惊为天人,对于将Web应用程序做到与桌面程序非常相似,深深地佩服。在决定采用ExtJS之后,真正的苦头就来了,首先要研究ExtJS提供的大量文件,深入了解项目所需要用到的组件,然后还要研究看起来像天书一样的JavaScript(当时对笔者对面向对象式JavaScript还不熟悉),再加上当时的除错工具非常落伍,只能alert(msg)的方式。遇到部分组件与预期的想法不同时,还要追进去原始码,想办法了解并解决,开发起来非常耗费精神。

简单来说,要利用ExtJS开发的时候,必须要深入了解其各式组件的用法,并以Java script开发。在企业内如果要使用ExtJS,除了学习曲线长外,开发人员在开发时仍要小心跨浏览器的问题。

EZo Engine

现在有这些困扰的开发者,可以选择一个新的技术,叫做EZo Engine。其架构如下:


EZo Engine运作架构

此技术利用XML的语法来描述画面,由前台加载的解译引擎对XML进行剖析后,转成ExtJS组件来呈现。而前台组件可以利用事件的方式,直接与后台的组件沟通,所有组件内的数据内容都会被转成JSON格式,后台的组件收到数据即可处理并响应。其中EZo Engine扮演前后台的沟通桥梁,让开发者使用起来感觉是透通的,能非常方便的完成AJAX应用程序。EZo Engine也整合了spring框架,只要是spring的bean,在前台就能直接将数据传给指定的bean。

例如,要呈现如下图的Grid组件:


翻页清单画面

其语法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<page>   <contentPanel heading='部门维护作业' style='margin:0 auto;' width='60%' borders='true'>     <form headerVisible='false' align='right'>       <field type='trigger' label='部门' width='80%'/>     </form>     <grid id='g1' page='true' type='edit' headerVisible='false'>       <field type='txt' label='代码' columnWidth='25'></field>       <field type='txt' label='名称' columnWidth='30'></field>       <field type='txt' label='别名' columnWidth='30'></field>       <field type='comboBox' label='状态' columnWidth='15'>正常:1,作废:0</field>     </grid>     <js init='js:this'>       var data = [{
        '代码':'A1',
        '名称':'XXX',
        '别名':'',
        '状态':'正常'       },{'代码':'A2',
        '名称':'YYY',
        '别名':'',
        '状态':'正常'       },{'代码':'A3',
        '名称':'ZZZ',
        '别名':'',
        '状态':'正常'       },{'代码':'A4',
        '名称':'WWW',
        '别名':'',
        '状态':'正常'       }];
      gk.set('g1',data);
    </js>     </contentPanel>      </page>     

其中<contentPanel>是在画面上先布置一个Panel,并利用style属性设定该Panel置中。再使用<grid>以及<field>,即可呈现出Grid的样子。其中将<grid>的page属性设定为true,即可具备分页功能,type属性设定为edit,则字段即显示为输入字段。后面的<js>,只是为了显示数笔数据在Grid内,真正开发时则是透过事件传送给后台的spring bean来取得数据。

相信曾利用ExtJS开发的人,一定很惊讶其大幅减少开发程序代码的幅度,原本要呈现Grid组件所需要的Column、PagingToolbar等繁复设定,在这个例子都被简化了。而使用XML的方式来表达画面,对开发人员而言是更为直觉的,因为这样的方式很类似HTML的语法,如果是熟悉ExtJS的开发人员,则入手更为容易。

范例

接下来我们将实际例子比较采用ExtJS与EZo Engine两种开发方式的差异。

我们以用户基本数据维护作为例子,其画面如下图。左侧为用户查询列表,点选数据则连动到右侧的窗体,可执行用户数据的新增、修改、删除。后台组件则是以spring框架整合。


使用者账号维护画面

底下将从不同面向讨论。

画面布局(Layout)

此画面采用Border Layout,只用到west与center两个区域。

使用ExtJS的方式,必须先利用Viewport,让画面可以扩及整个浏览器页面。

1
2
3
4
5
6
7
    var vp = new Ext.Viewport({
        layout: 'border',
        items: [
            userGrid,
            userForm         ]
    });

然后在userGird与userForm指定region属性,让用户列表位于左边且可缩放,窗体则位于右边。

GridPanel

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
    var userGrid = new Ext.grid.GridPanel({
        region:'west',
        split:true,
        height:210,
        minSize:200,
        maxSize:300,
        width:500,
        collapsible: true,
        store: store,
        sm: new Ext.grid.RowSelectionModel({
            singleSelect: true,
            listeners:{
                rowselect: function(sm, row, rec) {
                    userForm.getForm().loadRecord(rec);
                }
            }
        }),
        columns: [
            {id:'userId',header: '账号', width: 70, sortable: true, dataIndex: 'userId'},
            {header: '姓名', width: 70, sortable: true, dataIndex: 'name'},
            {header: '有效日期', width: 80, sortable: true, dataIndex: 'validDate', renderer: Ext.util.Format.dateRenderer('Y/m/d')},
            {header: '部门', width: 200, sortable: true, dataIndex: 'dept'},
            {header: '职称', width: 80, sortable: true, dataIndex: 'pos'}
        ],
        stripeRows: true,
        title:'用户清单',
        bbar: new Ext.PagingToolbar({
            pageSize : 10,
            store : store,
            displayInfo : true,
            displayMsg : '显示第 {0} 笔到 {1} 笔资料,一共 {2} 笔',
            emptyMsg : "没有资料"         })
    });

FormPanel

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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
68
69
70
71
72
73
74
75
76
77
78
79
80
    var userForm = new Ext.FormPanel({
        region:'center',
        height:500,
        labelWidth: 75,
        id: 'user-form',
        labelAlign: 'right',
        title: '用户基本数据维护',
        bodyStyle:'padding:5px 5px 0',
        width: 750,
        tbar: [
            {text:'新增', iconCls:'btnCls', handler:insertUser},
            {xtype:'tbspacer'},
            {text:'修改', iconCls:'btnCls', handler:updateUser},
            {xtype:'tbspacer'},
            {text:'删除', iconCls:'btnCls', handler:deleteUser},
            '->',
            {xtype:'tbtext', text:'讯息'},
            {xtype:'textfield', value:'查询完成', readOnly:true, width:150, style:'background:#fff;color:red;'}
        ],
        items: [{
            xtype:'fieldset',
            title:'基本数据',
            collapsed: false,
            autoHeight:true,
            defaults: {width: 350},
            defaultType: 'textfield',
            items:[{
                    fieldLabel: '账号',
                    name: 'userId',
                    allowBlank:false                 },{
                    fieldLabel: '姓名',
                    name: 'name'                 },{
                    xtype:'datefield',
                    fieldLabel: '有效日期',
                    name: 'validDate',
                    format: 'Y/m/d'             }]
        },{
            xtype:'fieldset',
            title:'附属数据',
            collapsed:false,
            collapsible :true,
            autoHeight:true,
            defaults: {width: 350},
            defaultType: 'textfield',
            items:[{
                fieldLabel:'别名',
                name:'aliaName'             },{
                xtype:'combo',
                fieldLabel:'性别',
                hiddenName:'sex',
                store:new Ext.data.SimpleStore({
                    fields: ['sex', 'desc'],
                    data :[
                        ['0','男'],
                        ['1','女']
                    ]
                }),
                valueField:'sex',
                displayField:'desc',
                triggerAction: 'all',
                mode: 'local',
                typeAhead: false,
                value:'0'             },{
                xtype:'trigger',
                triggerClass:'x-form-search-trigger',
                fieldLabel:'部门',
                name:'dept'             },{
                xtype:'trigger',
                triggerClass:'x-form-search-trigger',
                fieldLabel:'职称',
                name:'pos'             }]
        }]
    });

如采用EZo Engine来实现这个画面,则是很直觉的在<page>指定layout为border,然后在分别于<border>上指定region的属性即可,用起来直觉许多。

1
2
3
4
5
6
7
8
<page layout="border">   <border region='west' size='500' split='true' collapsible='true' margins='3'>     <!-- 略 -->   </border>   <border region='center' margins='3'>     <!-- 略 -->   </border> </page>     

分页清单(Grid with Paging)

要制作一个分页清单,利用ExtJS来开发至少要用到GridPanel、Store、DataReader、PagingToolbar等组件。

以此例子要做到列表与窗体连动功能,于点选列表时,将该笔数据呈现在窗体,还需要为RowSelectionModel组件添加rowselect事件才能完成。请参考GridPanel程序代码。

如采用EZo Engine来开发,则如下图。利用<grid>搭配<field>即可完成Grid,同时在onRow这个事件上,设定bean: dujcUserList.getUser:g1.row,表示要将Grid(id为g1)目前点选列的资料,传给后台spring bean的id为dujcUserList这个对象,并呼叫其getUser这个方法。在getUser方法内只要取出用户账号,从数据库查出该用户的详细数据,以窗体的id为键值存放到Map内,即可将数据呈现在窗体上。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  <border region='west' size='500' split='true' collapsible='true' margins='3'>     <contentPanel heading='用户清单' borders='true' style='padding:2px'>       <form headerVisible='false' align='right'>         <field type='trigger' id='userId_qry' label='使用者' value='ICSC01' width="80%" onClick='bean:dujcUserList.userList:userId_qry.value,g1,g1.pageBar'/>       </form>       <grid id='g1' page='true' headerVisible='false' init='bean:dujcUserList.userList:userId_qry.value,g1,g1.pageBar'           onRow='bean:dujcUserList.getUser:g1.row'>         <field type='label' label='账号' columnWidth='20'></field>         <field type='label' label='姓名' columnWidth='20' columnAlign='left'></field>         <field type='label' label='有效日期' columnWidth='20'></field>         <field type='label' label='部门' columnWidth='20'></field>         <field type='label' label='职称' columnWidth='20'></field>       </grid>     </contentPanel>   </border>     

在init属性设定bean:dujcUserList.userList:userId_qry.value,g1,g1.pageBar,表示起始的时候会将userId_qry这个查询字段的值,以及g1与g1.pageBar的数据,通通传送到dujcUserList这个对象的userList方法。这个方法则依据查询条件与分页条件,将符合数据传回前台呈现。

相信看到这里,读者一定非常惊讶EZo Engine居然能如此简单、直觉的就完成列表与窗体的连动,如采用ExtJS须要写上百行程序才成达成!

窗体(Form)

利用ExtJS制作一个维护窗体,至少需要FormPanel、TextField(含DateField、TriggerField、ComboBox等)、以及Button等对象。

在FormGrid程序代码内可以看到,于tbar属性去撰写每个按钮handler的方法,在该方法内去呼叫FormPanel组件的功能,透过AJAX方式将数据送到后台处理。而表单域也需要作特别处理。例如,在日期字段的格式,下拉选单的选项数据,提示字段(trigger field)的事件处理,都需要额外撰写不少的程序代码,对开发者而言,打造一个ExtJS程序真是不容易的工作。

在EZo Engine这边则利用<toolbar>与<fieldset>即可很快的组出功能列,再利用<fieldset>、<form>、以及<field>来组出窗体的长相。

然后只要在按钮加上onClick的事件,将窗体数据传给后台适当的对象处理,即可很快的完成这个画面的功能。例如,新增按钮在onClick事件设定为bean:dujcUserList.create:userBasic,userExtend,其中bean:dujcUserList.create表示要将数据传送的dujcUserList这个spring bean的create方法;而userBasic,userExtend则表示为基本数据与附属数据这两个<form>的id,EZo Engine会将该这两个窗体的数据传送到后台。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
  <border region='center' margins='3'>     <contentPanel heading='用户基本数据维护' borders='true' style='padding:2px'>       <toolbar id='toolbar' borders='false'>         <field type="btn" label="新增" width="60" onClick="bean:dujcUserList.create:userBasic,userExtend"/>         <field type="btn" label="修改" width="60" onClick="bean:dujcUserList.update:userBasic,userExtend"/>         <field type="btn" label="删除" width="60" onClick="bean:dujcUserList.delete:userBasic,userExtend"/>       </toolbar>       
      <fieldset heading='基本数据'>         <form id='userBasic' headerVisible='false' align='right'>           <field type='txt' label='账号' width='50%'/>           <field type='txt' label='姓名' width='50%'/>           <field type='date' label='有效日期' width='50%'/>         </form>       </fieldset>       <fieldset heading='附属数据' collapsible='true'>         <form id='userExtend' headerVisible='false' align='right'>           <field type='txt' label='别名' width='50%'/>           <field type='comboBox' id='combo1' label='性别' width='50%'>女:0,男:1</field>           <formRow widthRate='50%,0:50%'>               <field type='trigger' label='部门' width='100%'/>             <field type='label' id='deptName' width='100%'/>           </formRow>           <formRow widthRate='50%,0:50%'>               <field type='trigger' label='职称' width='100%'/>             <field type='label' id='postName' width='100%'/>           </formRow>           <field type='txt' label='电子邮件' width='50%'/>         </form>       </fieldset>     </contentPanel>   </border>     

结论

在上述这个例子里,我们很快的体验到EZo Engine所带给我们简单、快速的开发方式,不用再写一大堆Java script,也不需要面对像天书一样的JSON格式语法。只要透过XML的描述加上后台的spring bean,就能轻松的开发,相信不管是个人开发者或是企业内开发人员,都能快速的打造易用、美观的网页应用系统,而且最重要的是再也不用担心不小心写到无法跨浏览器的Java script,可以节省测试的时间。

举报
陈威宇
发帖于5年前 8回/502阅
顶部