第三节 Ext表格控件和树控件

longlin 贡献于2011-06-23

作者 Chinese User  创建于2009-04-15 03:02:00   修改者雨林木风  修改于2011-02-27 12:04:00字数18702

文档摘要:第三节 Ext表格控件和树控件学习目标:1.掌握GridPanel、EditorGridPanel和TreePanel的用法 <br> 2.掌握三种Store、TreeLoader的用法
关键词:

蓝杰java讲习录 只为不凡而来 www.NetJava.cn 第三节 Ext表格控件和树控件 学习目标: 1. 掌握GridPanel、EditorGridPanel和TreePanel的用法 2.掌握三种Store、TreeLoader的用法 目录 第三节 Ext表格控件和树控件 1 1. 表格控件 2 1.1基本表格 GridPanel 2 1.2可编辑的表格EditorGridPannel 5 2.与服务器交互 8 3. 数据存储Store 10 3.1存放数据的类Record 10 3.2 Store数据存储器 10 3.3 DateReader数据读取器 11 4 DataProxy数据代理 13 5. 树控件TreePanel 15 5.1 TreePanel基本应用 15 5.2 事件处理 17 5.3 树加载器TreeLoader 18 5.4 自定义TreeLoader 20 任务和总结: 20 蓝杰 陈九龙 QQ:89715761 蓝杰java讲习录 只为不凡而来 www.NetJava.cn 1. 表格控件 1.1基本表格 GridPanel ExtJS中的表格功能非常强大,包括了排序、缓存、拖动、隐藏某一列、自动显示行号、列汇总、单元格编辑等实用功能。 表格由类Ext.grid.GridPanel定义,继承自Panel,其xtype为grid。ExtJS中,表格Grid必须包含列定义信息,并指定表格的数据存储器Store。表格的列信息由类Ext,grid.ColumnModel定义,而表格的数据存储器由Ext.data.Store定义,数据存储器根据解析的数据不同分为JsonStore、SimpleStore、GroupinStore等。我们看一个简单的使用表格控件的代码: Ext.onReady(function(){ var data=[ [1, '任务管理系统', '3D','www.renwu.com'], [2, 'Blog系统', 'BJT','www.blog.org'], [3, 'Ext管理系统', '3d','www.Extrw.com'], [4, '中流网', 'ZLW','www.zlweb.cn'] ]; var store=new Ext.data.SimpleStore({ data:data, fields:["id","name","organization","homepage"] }); var grid = new Ext.grid.GridPanel({ renderTo:"hello", title:"NetJava表格测试", height:150, width:600, columns:[{header:"项目名称",dataIndex:"name"}, {header:"开发团队",dataIndex:"organization"}, {header:"网址",dataIndex:"homepage"}], store:store, autoExpandColumn:2 }); }); 运行上面的代码,可以得到一个简单的表格如下: 上面的代码中,第一行“var data-…”用来定义表格中要显示的数据,这是一个[][]二维数组;第二行”var store=…”用来创建一个数据存储,这是GridPannel需要使用配置属性,数据存储器Store负责把各种各样的数据(如二维数组、JSon对象数组、XML文本)等转换成ExtJS的数据记录集Record,关于数据存储器Store我们将会在下一节中作专门讲解。第三行 蓝杰java讲习录 只为不凡而来 www.NetJava.cn ”var grid=new Ext.grid.GridPannel(…)”负责创建一个表格,表格包含的列由columns配置属性来描述,columns是一个数组,每一行数据元素描述表格的一列信息。表格的列信息包含列头显示的文本(header)、列对应的记录集字段(dataIndex)、列是否可排序(sorable)、列的渲染函数(renderer)、格式化信息(format)等,在上面的列中只用到了header和dataIndex. 下面我们再来看看表格控件的其它一些特性,修改一下上面的代码,内容如下: function showUrl(value){ return ""+value+""; } Ext.onReady(function(){ var data=[ [1, '任务管理系统', '3D','http://www.renwu.com'], [2, 'Blog系统', 'BJT','http://www.blog.org'], [3, 'Ext管理系统', '3d','http://www.Extrw.com'], [4, '中流网', 'ZLW','http://www.zlweb.cn'] ]; var store=new Ext.data.SimpleStore({data:data,fields:["id","name","organization","homepage"]}); var colM=new Ext.grid.ColumnModel([ {header:"项目名称",dataIndex:"name",sortable:true}, {header:"开发团队",dataIndex:"organization",sortable:true}, {header:"网址",dataIndex:"homepage",sortable:true,renderer:showUrl}]); var grid = new Ext.grid.GridPanel({ renderTo:"hello", title:"NetJava表格测试", height:150, width:600, cm:colM, store:store, autoExpandColumn:2 }); }); 上面的代码直接使用Ext.grid.ColumnModel来创建表格的列定义信息,在各列中我们添加了sortable为true的属性,表示该列可以排序,另外,买一列的数据渲染方式还可以自己定义,比如上面的代码中,我们希望用户在表格中点击网址可以打开这些团队的网站,也就是给网址这一列添加了超连接,运行效果如下: 蓝杰java讲习录 只为不凡而来 www.NetJava.cn 在定义“网址”的时候加上renderer属性:renderer:showUrl。showUrl是一个自定义的函数,内容是根据传入的value参数返回一个包含标签的html片段。自定义的列渲染函数可以实现在单元格中显示自己所需要的各种信息,只要是浏览器支持的html都可以。 除了二维数组以外,表格还能显示其它格式的数据吗,这个是当然的,下面我们来看个例子,将数据定义为以下格式: var data=[{id:1, name:'任务管理系统', organization:'3D', homepage:'http://www.renwu.com'}, {id:2, name:'Blog系统', organization:'BJT', homepage:'http://www.renwu.com'}, {id:3, name:'Ext管理系统', organization:'3D', homepage:'http://www.Extrw.com'}, {id:4, name:'中流网', organization:'ZLW', homepage:'http://www.zlweb.cn'} ]; 也就是说数据变成了一维数组,数组中的每一个元素是一个对象,这些对象包含"id", "name","organization","homepage" 等属性,要让表格上显示上面的数据,只要将存储器store改为Ext.data.JsonStore即可,如下: var store=new Ext.data.JsonStore({data:data,fields:["id","name","organization","homepage"]}); 上面的代码执行的结果与前面的一样。另外,表格同样能显示xml格式的数据,将上面的数据存放成store.xml文件,如下: 1 任务管理系统 3D http://www.renwu.com 2 Blog系统 BJT http://www.renwu.com 蓝杰java讲习录 只为不凡而来 www.NetJava.cn 3 Ext管理系统 3D http://www.Extrw.com 4 中流网 ZLW http://www.zlweb.cn 将js代码数据存储器部分改为: function showUrl(value){ return ""+value+""; } Ext.onReady(function(){ var store=new Ext.data.Store({ url:"tab.xml", reader:new Ext.data.XmlReader({record:"row"},["id","name","organization","homepage"]) }); var colM=new Ext.grid.ColumnModel([ {header:"项目名称",dataIndex:"name",sortable:true}, {header:"开发团队",dataIndex:"organization",sortable:true}, {header:"网址",dataIndex:"homepage",sortable:true,renderer:showUrl} ]); var grid = new Ext.grid.GridPanel({ renderTo:"hello", title:"NetJava表格测试", height:150, width:600, cm:colM, store:store, autoExpandColumn:2 }); store.load(); }); Store.load()是用来加载数据,执行上面的代码产生的表格与前面的完全一样。 1.2可编辑的表格EditorGridPannel 可编辑表格是指可以直接在表格的单元格对表格的数据进行编辑,ExtJS中的可编辑表格由类Ext.grid.EditorGridPanel表示,xtype为editorgrid。使用EditorGridPanel与使用普通的GridPanel方式一样,区别只是在定义列信息的时候,可以指定某一列使用的编辑即可,下面来看一个简单的示例。 蓝杰java讲习录 只为不凡而来 www.NetJava.cn Ext.onReady(function(){ var data=[{id:1, name:'小王', email:'xiaowang@easyjf.com', sex:'男', bornDate:'1991-4-4'}, {id:1, name:'小李', email:'xiaoli@easyjf.com', sex:'男', bornDate:'1992-5-6'}, {id:1, name:'小兰', email:'xiaoxiao@easyjf.com', sex:'女', bornDate:'1993-3-7'} ]; var store=new Ext.data.JsonStore({ data:data, fields:["id","name","sex","email",{name:"bornDate",type:"date",dateFormat:"Y-n-j"}] }); var colM=new Ext.grid.ColumnModel([ {header:"姓名", dataIndex:"name", sortable:true, editor:new Ext.form.TextField() }, {header:"性别", dataIndex:"sex", editor:new Ext.form.ComboBox({transform:"sexList",triggerAction:"all",lazyRender:true}) }, {header:"出生日期", dataIndex:"bornDate", width:120, renderer:Ext.util.Format.dateRenderer('Y年m月d日'), editor:new Ext.form.DateField({format:'Y年m月d日'}) }, {header:"电子邮件", dataIndex:"email", 蓝杰java讲习录 只为不凡而来 www.NetJava.cn sortable:true, editor:new Ext.form.TextField() } ]); var grid = new Ext.grid.EditorGridPanel({ renderTo:"hello", title:"学生基本信息管理", height:200, width:600, cm:colM, store:store, autoExpandColumn:3, clicksToEdit:1, }); }); 上面的代码首先定义了一个包含学生信息的对象数组,然后创建了一个JsonStore对象,在创建这个store的时候,指定了bornDate列的类型为日期Date类型,并使用dateFormat来指定日期信息的格式为”Y-n-j”,Y表示年,n表示月,j表示日。定义表格模型的时候,对于“姓名”及“电子邮件”列我们使用editor类定义该列使用的编辑器,这使用的Ext.form.TextField,最后使用new Ext,grid,EditorGridPanel(…)来创建一个可编辑的表格。执行上面的程序可以生成一个表格,最后在定义EditorGridPanel的时候,我们定义了一个clicksToEdit属性,表示点击一个单元格即触发编辑,默认情况下,该属性的值是2,需要点击两次才能触发,单击表格中的“姓名”或“电子邮件”单元格中的信息可以触发单元格编辑,可以在单元格的文本框中直接编辑表格中的内容,修改过后的单元格会有特殊的标记。 为了能编辑“性别”及“出生日期”列,同样只需要在定义该列的时候指定editor即可。由于出生日期是日期类型,因此我们可以使用日期编辑器来编辑,“性别”一列的数据不应该让用户直接输入,而应该是通过下拉框进行选择。日期编辑器可以直接使用Ext.form.DateField组件,下拉选择框编辑器可以使用Ext.form.ComboBox组件,另外,在页面的body中间,需要加上下面的代码: 执行上面的代码,当我们单击一个单元格的时候,就会得到如下的几种效果: 蓝杰java讲习录 只为不凡而来 www.NetJava.cn 还有一点就是,当我们修改了数据之后,如何保存呢?请继续往下看。 2.与服务器交互 在实际的应用中,表格中的数据一般都是直接存放在数据库表或服务器的文件中。因此,在使用表格控件的时候经常要与服务器进行交互。ExtJS使用Ajax方式提供了一套与服务器交互的机制,也就是可以不用刷新页面,就可以直接访问服务器的程序进行数据读取或数据保存等操作。 比如,在前面的例子中显示xml文档中数据的例子,就是一个非常简单的从服务器端读取数据的例子,再回顾以下代码: var store=new Ext.data.Store({ url:"tab.xml", reader:new Ext.data.XmlReader({record:"row"},["id","name","organization","homepage"]) }); 因为Store组件接收一个参数url,则ExtJS会创建一个与服务器交互的Ext.data.HttpProxy对象,该对象通过指定的Connection或Ext.Ajax.request来向服务器端发送请求,从而可以读取服务器端的数据。 一般情况下,我们通过在服务器端生成JSon数据,也就是说假如服务器端的url是”student.netjava?cmd=list”产生的JSon数据输出如下: {results: [{id:1, name:'任务管理系统', organization:'3D', homepage:'http://www.renwu.com'}, {id:2, 蓝杰java讲习录 只为不凡而来 www.NetJava.cn name:'Blog系统', organization:'BJT', homepage:'http://www.renwu.com'}, {id:3, name:'Ext管理系统', organization:'3D', homepage:'http://www.Extrw.com'}, {id:4, name:'中流网', organization:'ZLW', homepage:'http://www.zlweb.cn'} ] } 则在前面显示学习信息编辑表格的store可以创建成下面的形式: var store=new Ext.data.Store({ url:"student.netjava?cmd=list", reader:new Ext.data.JsonReader({ root:"result"}, ["id","name","organization","homepage"]) }); 或者: var store=new Ext.data.JsonStore({ url:"student.netjava?cmd=list", root:"result", fields:["id","name","organization","homepage"] }); 其中root表示包含记录集数据的属性。         如果在运行程序中需要给服务器端发送数据的时候,此时可以直接使用ExtJS中提供的Ext.Ajax对象的request方法。比如下面的代码实现放服务器的student. netjava?cmd=save这个url发起一个请求,并在params中指定发送的Student对象: function sFn() { alert('保存成功'); } function fFn() { alert('保存失败'); } Ext.Ajax.request({ url: 'student.netjava?cmd=save’, success: sFn, failure: fFn, params: { name: '小李',email: ' xiaoli@netjava.com',bornDate: ' 蓝杰java讲习录 只为不凡而来 www.NetJava.cn 1992-5-6',sex: '男'} }); 3. 数据存储Store 在前面的表格应用中,我们已经知道表格的数据是存放类型为Store的数据存储器中,通过指定表格Grid的store属性来设置表格中显示的数据,通过调用store的load或reload方法可以重新加载表格中的数据。ExtJS中用来定义控件中使用数据的API位于Ext.dd命名空间中,本章我们重点对ExtJS中的数据存储Store进行介绍。 3.1存放数据的类Record 首先需要明确是,ExtJS中有一个名为Record的类,表格等控件中使用的数据是存放在Record对象中,一个Record可以理解为关系数据表中的一行,也可以称为记录。Record对象中即包含了记录(行中各列)的定义信息(也就是该记录包含哪些字段,每一个字段的数据类型等),同时又包含了记录具体的数据信息(也就是各个字段的值)。 我们来看直接使用Record的代码: Ext.onReady(function(){ var MyRecord=Ext.data.Record.create([ {name:'title'}, {name:'username',mapping:'author'}, {name:'loginTimes',type:'int'}, {name:'lastLoginTime',mapping:'loginTime',type:'date'} ]); var r=new MyRecord({ title:"日志标题", username:"netjava", loginTimes:100, loginTime:new Date() }); alert(MyRecord.getField("username").mapping); alert(MyRecord.getField("lastLoginTime").type); alert(r.data.username); alert(r.get("loginTimes")); }); 首先是使用Record的Create方法创建一个记录集MyRecord, MyRecord其实是一个类,该类包含了记录集的定义信息,可以通过MyRecord来创建包含字段值的Record对象。在上面的代码中,最后的几条语句用来输出记录集的相关信息,MyRecord.getField("username")可以得到记录中username列的字段信息,r.get("loginTimes")可以得到记录loginTimes字段的值,而r.data.username同样能得到记录集中username字段的值。对Record有了一定的了解,那么要操作记录集中的数据就非常简单了,比如r.set(name,value)可以设置记录中某指定字段的值,r.dirty可以得到当前记录是否有字段的值被更改过等等。 3.2 Store数据存储器 Store可以理解为数据存储器,可以理解为客户端的小型数据表,提供缓存等功能。在ExtJS中,GridPanel、ComboBox、DataView等控件一般直接与Store打交道,直接通过store来获得控件中需要展现的数据等。一个Store包含多个Record,同时Store又包含了数据来源,数据解析器等相关信息,Store通过调用具体的数据解析器(DataReader)来解析指定类型或格式的数据(DataProxy),并转换成记录集的形式保存在Store中,作为其它控件的数据输入。 蓝杰java讲习录 只为不凡而来 www.NetJava.cn 数据存储器由Ext.data.Store类定义,一个完整的数据存储器要知道数据源(DataProxy)及数据解析方式(DataReader)才能工作,在Ext.data.Store类中数据源由proxy配置属性定义、数据解析(读取)器由reader配置属性定义,一个较为按部就班创建Store的代码如下: var MyRecord=Ext.data.Record.create([ {name:'title'}, {name:'username',mapping:'author'}, {name:'loginTimes',type:'int'}, {name:'lastLoginTime',mapping:'loginTime',type:'date'} ]); var dataProxy=new Ext.data.HttpProxy({url:"link.netjava"}); var theReader=new Ext.data.JsonReader({ totalProperty:"results", root:"rows", id:"id" },MyRecord); var store=new Ext.data.Store({ proxy:dataProxy, reader:theReader }); store.load(); 当然,这样的难免代码较多,Store中本身提供了一些快捷创建Store的方式,比如上面的示例代码中可以不用先创建一个HttpProxy,只需要在创建Store的时候指定一个url配置参数,就会自动使用HttpProxy来加载参数;并在Store的基础上进行封装,提供了SimpleStore、GroupingStore等,直接使用SimpleStore。这样,上面的代码就可以简化为: var store=new Ext.data.JSonStore({ url:"link.netjava?cmd=list", totalProperty:"results", root:"rows", fields:['title', {name:'username',mapping:'author'}, {name:'loginTimes',type:'int'}, {name:'lastLoginTime',mapping:'loginTime',type:'date'} ] }); store.load(); 3.3 DateReader数据读取器 DataReader表示数据读取器,也就是数据解析器,其负责把从服务器或者内存数组、xml文档中获得的杂乱信息转换成ExtJS中的记录集Record数据对象,并存储到Store里面的记录集数组中。数据解析器的基类由Ext.data.DataReader定义,其它具体的数据解析器都是该类的子类,ExtJS中提供了读取二维数组、JSon数据及Xml文档的三种数据解析器,分别用于把内存中的二级数组、JSON格式的数据及XML文档信息解析成记录集。下面简单的介绍: 蓝杰java讲习录 只为不凡而来 www.NetJava.cn 3.3.1 数组解析器ArrayReader Ext.data.ArrayReader是一个数组解析器,用于读取二维数组,并将结果集转换成记录集Record对象,请看如下的代码: var MyRecord=Ext.data.Record.create([ {name:'title',mapping:1}, {name:'username',mapping:2}, {name:'loginTimes',type:3} ]); var myReader=new Ext.data.ArrayReader({id:0},MyRecord); 这里的MyReader可以读取如下的二维数组: [[1,”测试”,”NetJava”,3],[2.”测试2”,”蓝杰”,11]] 3.3.2 数据解析器JsonReader Ext.data.JsonReader-Json数据解析器,用于读取JSON格式的数据信息,并转换成记录集Record对象。看下面使用JsonReader的代码: var MyRecord=Ext.data.Record.create([ {name:'title'}, {name:'username',mapping:'author'}, {name:'loginTimes',type:'int'} ]); var myReader=new Ext.data.JsonReader({ totalProperty:"results", root:"rows", id:"id"},MyRecord); 这里的JsonReader可以解析下面的JSON数据: {'results':2,'rows':[ {id:1,title:'测试',author:'小王',loginTimes:3}, {id:2,title:'Ben',author:'williamraym',loginTimes:13}] } JSonReader还有比较特殊的用法,就是可以把Store中记录集的配置信息存放直接保存在从服务器端返回的JSON数据中,比如下面的例子: var myReader=new Ext.data.JsonReader(); 这一个不带任何参数的myReader,可以处理从服务器端返回的下面JSON数据: { 'metaData':{ totalProperty:'results', root:'rows', id:'id', fields:[ {name:'title'}, {name:'username',mapping:'author'}, {name:'loginTimes',type:'int'}] }, 'results':2,'rows':[ {id:1,title:'测试',author:'小王',loginTimes:3}, 蓝杰java讲习录 只为不凡而来 www.NetJava.cn {id:2,title:'新年好',author:'蓝杰',loginTimes:13}] } 3.3.2 数据解析器XmlReader Ext.data.XmlReader-XML文档数据解析器,用于把XML文档数据转换成记录集Record对象。看下面的代码: var MyRecord=Ext.data.Record.create([ {name:'title'}, {name:'username',mapping:'author'}, {name:'loginTimes',type:'int'} ]); var myReader=new Ext.data.XmlReader({ totalRecords:"results", record:"rows", id:"id"}, MyRecord); 上面的myReader能够解析下面的xml文档信息: 2 1 测试 小王 3 2 新年好 williamraym 13 4 DataProxy数据代理 DataProxy字面解释就是数据代理,也可以理解为数据源,也即从哪儿或如何得到需要交给DataReader解析的数据。数据代理(源)基类由Ext.data.DataProxy定义,在DataProxy的基础,ExtJS提供了Ext.data.MemoryProxy、Ext.data.HttpProxy、Ext.data.ScriptTagProxy等三个分别用于从客户端内存数据、Ajax读取服务器端的数据及从跨域服务器中读取数据等三种实现。 4.1 MemoryProxy MemoryProxy只能从Javascript对象获取数据,可以直接把数组、JSON或XML格式的数据交给它处理,代码如下: var proxy = new Ext.data.MemoryProxy([   ['id1','name1','netjava1'], 蓝杰java讲习录 只为不凡而来 www.NetJava.cn   ['id2','name2','netjava2']   ]); 4.2 HttpProxy HTtpProxy使用HTTP协议,通过Ajax去后台取数据,构造它时需要设置url:’xxx.jsp’参数。这里的url可以是任何一个合法的网址,告诉HttpProxy应该去哪里获取数据,如下代码所示: var proxy = new Ext.data.HttpProxy({url:'xxx.jsp'}); 后台需要返回Ext所需要的JSON格式的数据。下面是一个后台使用jsp的示例: response.setContentType("application/x-json");   Writer out = response.getWriter();   out.print("[" +   "['id1','name1','netjava1']" +   "['id2','name2','netjava2']" +   "]"); 请注意,这里的HttpProxy不支持跨域,它只能从同一域中获得数据。如果想跨域,请看下面的ScriptTagProxy。 4.3 ScriptTagProxy ScriptTagProxy的用法几乎和HttpProxy一样,如下面的代码所示: var proxy = new Ext.data.ScriptTagProxy({url:'xxx.jsp'});  从这里也看不出来它是如何支持跨域的,我们还需要在后台进行相应的处理,如下面的代码所示: String cb = request.getParameter("callback");   response.setContentType("text/javascript");   Writer out = response.getWriter();   out.write(cb + "(");   out.print("[" +   "['id1','name1','netjava1']" +   "['id2','name2','netjava2']" +   "]");   out.write(");"); 其中关键的参数就在于从请求中获得的callback参数,这个参数叫回调函数。Script-Proxy会在当前的Html页面中添加一个标签,然后把后台返回的内容添加到这个标签中,这样就可以解决跨域访问数据的问题。为了让后台返回的内容可以在动态生成的标签中运行,Ext会生成一个名为callback的回调函数,并把回调函数的名称传递给后台,由后台生成callback(data)形式的响应内容,然后返回给前台自动运行。 上述处理过程比较难理解,我们只需要了解ScriptTagProxy的用法就足够了。如果还想进一步了解ScriptTagProxy的运行过程,可以使用Firebug查看动态生成的HTML以及响应的JSON内容。 最后我们来看下面这个示例,这段后台代码会自动判断请求的类型,返回支持ScriptTagProxy或HttpProxy的数据,如代码如下: boolean scriptTag = false;   String cb = request.getParameter("callback");   if (cb != null) {   scriptTag = true;   response.setContentType("text/javascript");   } else {    response.setContentType("application/x-json");   } 蓝杰java讲习录 只为不凡而来 www.NetJava.cn   Writer out = response.getWriter();   if (scriptTag) {    out.write(cb + "(");   }    out.print(dataBlock.toJsonString());   if (scriptTag) {    out.write(");");   } 在实际应用中,除了基本的从内存中读取javascript数组对象,从服务器读取JSON数组,从服务器取xml文档等形式的数据外,有时候还需要使用其它的数据读取方式。比如熟悉DWR框架的都知道,通过这些框架我们可以直接在客户端使用javascript调用服务器端业务组件的方法,并把服务器端的结果返回到客户端,客户端得到的是一个javascript对象或数组。由于这种方式的调用是异步的,因此,相对来说有点特殊,即不能直接使用Ext.data.MemoryProxy,也不能直接使用Ext.data.HttpProxy,当然更不需要Ext.data.ScriptTagProxy,这时候就需要创建自定义的DataProxy及Store,然后使用这个自定义的Store来实现这种基于远程脚本调用引擎的框架得到数据。我们将在后面详细介绍自定义Store来实现。 5. 树控件TreePanel 在应用程序中,我们经常会涉及到要显示或处理树状结构的对象信息,比如部门信息、地区信息,或者是树状的菜单信息,操作系统中的文件夹信息等。 对于传统的html页面来说,要自己实现显示树比较困难,需要写很多的javascript,特别是对于基于Ajax异步加载的树来说,不但涉及到Ajax数据加载及处理技术,还需要考虑跨浏览器支持等,处理起来非常麻烦。ExtJS中提供了现存的树控件,通过这些控件可以在B/S应用中快速开发出包含树结构信息的应用。 5.1 TreePanel基本应用 树控件由Ext.tree.TreePanel类定义,控件的名称为treepanel,TreePanel类继承自Panel面板。在ExtJS中使用树控件其实非常简单,我们先来看下面的代码: Ext.onReady(function(){ //创建根节点 var root = new Ext.tree.TreeNode({ text : '根节点' }); //为根节点添加子节点 root.appendChild(new Ext.tree.TreeNode({ text : '一级子节点A' })) root.appendChild(new Ext.tree.TreeNode({ text : '一级子节点B' })) //创建Tree面板组件 var tree = new Ext.tree.TreePanel({ 蓝杰java讲习录 只为不凡而来 www.NetJava.cn title : '简单的树面板示例', width : 200, height : 100, applyTo : 'hello', root : root }) }); 代码的第一句使用newExt.tree.TreeNode类来创建一个树节点,第二句使用树节点的root的appendChild方法来往该节点中加入一个子节点,最后直接使用newExt.tree.TreePanel来创建一个树面板,要树面板的初始化参数中指定树的root属性值为前面创建的root节点,也就是树根节点。上面的程序执行效果如下图所示:树的节点信息。ExtJS的树控件提供了对这种功能的支持,你只需要在创建树控件的时候,通过给树指定一个节点加载器,可以用来从服务器端动态加载树的节点信息。我们来看下面的代码: Ext.onReady(function(){ //创建根节点 var root = new Ext.tree.AsyncTreeNode({ text : '菜单根节点', id : 'root', //设置异步树节点的数据加载器 loader : new Ext.tree.TreeLoader({ dataUrl : 'AsyncTreeNodeServer.jsp' }) }); //创建Tree面板组件 var tree = new Ext.tree.TreePanel({ title : '异步加载树节点示例', width : 200, height : 150, applyTo : 'hello', root : root }); }); AsyncTreeNodeServer.jsp这个url返回的内容如下: <%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <% String nodeId = request.getParameter("node"); System.out.println("nodeId="+nodeId); StringBuffer tree = new StringBuffer(); if(nodeId.equals("root") == true){ tree.append("["); tree.append("{id:'level1-1',text:'一级节点',leaf:true,cust:'server'},"); tree.append("{id:'level1-2',text:'一级节点',leaf:false},"); tree.append("{id:'level1-4',text:'一级节点',leaf:true}"); tree.append("]"); 蓝杰java讲习录 只为不凡而来 www.NetJava.cn }else{ tree.append("["); tree.append("{id:'level2-1',text:'二级节点',leaf:true},"); tree.append("{id:'level2-4',text:'二级节点',leaf:true}"); tree.append("]"); } response.getWriter().write(tree.toString()); %> 执行上面的程序,可以得到一棵异步加载子节点的树,点击“根节点”会到服务器端加载子节点,如下图所示: 5.2 事件处理 当然,仅仅能显示一棵树还不够,我们一般还需要在用户点击树节点的时候执行相应的东西,比如打开某一个连接,执行某一个函数等,这就需要使用到事件处理。比如下面的代码: Ext.onReady(function(){ var root=new Ext.tree.TreeNode({ id:"root", text:"树的根"}); var c1=new Ext.tree.TreeNode({ id:"c1", text:"子节点" }); root.appendChild(c1); var tree=new Ext.tree.TreePanel({ title:'树的点击事件', width:200, height:150, renderTo:"hello", root:root, width:100 }); tree.on("click",function(node,event){ alert("您点击了"+node.text); } ); c1.on("click",function(node,event){ alert("您点击了"+node.text); 蓝杰java讲习录 只为不凡而来 www.NetJava.cn }); }); 执行上面的程序,当用户点击树控件中的任意节点时,都会弹出一个提示信息框,当用户点击c1这个子节点时,会弹出两次提示信息框。因为我们除了指定tree的click事件响应函数以外,另外又给node节点指定单独的事件响应函数。 当然,如果只是要实现当点击树节点时跳到某一个指定url的功能则非常简单。请看下面的代码: Ext.onReady(function(){ var root=new Ext.tree.TreeNode({ id:"root", href:"http://www.netjava.cn", hrefTarget:"_blank", text:"树的根"}); var c1=new Ext.tree.TreeNode({ id:"c1", href:"http://wlr.netjava.cn", hrefTarget:"_blank", text:"子节点" }); root.appendChild(c1); var tree=new Ext.tree.TreePanel({ title:'树的点击事件', width:200, height:150, renderTo:"hello", root:root, width:100 }); }); 5.3 树加载器TreeLoader 树加载器Ext.tree.TreeLoad提供了对子节点的延时加载功能,它请求指定的URL地址,接收返回的子节点的数据,它请求服务器返回的数据格式如下: [{ id:1, text:'子节点1', 蓝杰java讲习录 只为不凡而来 www.NetJava.cn leaf:true },{ id:2, text:'儿子节点2', children:[{ id:3, text:'孙子节点', leaf:true }] }] 当一个节点展开时一个加载子节点的请求被发送到服务器,当前节点的id会作为请求的参数被发送到服务器,在服务端可以通过node请求参数名进行运行获取,如果需要向服务器传递其他参数可以指定树加载器的beforeload事件,在事件处理函数中设置树加载器的baseParams属性,如: myTreeLoader.on("beforeload",function(treeLoader,node){ this.baseParamscategory = node.attributes.category; },this); 下面看一个完整的异步加载树节点的示例: Ext.onReady(function(){ //创建根节点 var root = new Ext.tree.AsyncTreeNode({ text : '菜单根节点', expanded : true,//设置根节点默认是展开的 id : 'root' }); //创建Tree面板组件 var tree = new Ext.tree.TreePanel({ tbar : [{ text : '取得被选节点', handler : function(){ var sm = tree.getSelectionModel();//取得树的选择模式对象 var node = sm.getSelectedNode();//取得当前选中的节点 alert('自定义属性cust:' + node.attributes.cust); } },{ text : '重新加载', handler : function(){ var loader = tree.getLoader();//取得树加载器 loader.load(root,function(){ root.expand();//重新加载后展开根节点 });//重新加载根节点 } }], //设置异步树节点的数据加载器 loader : new Ext.tree.TreeLoader({ baseAttrs : {//设置子节点的基本属性 蓝杰java讲习录 只为不凡而来 www.NetJava.cn cust : 'client' }, dataUrl : 'AsyncTreeNodeServer.jsp'//设置请求地址 }), title : 'TreeLoader示例', width : 200, height : 150, applyTo : 'hello', root : root }); }); 运行效果如下: 5.4 自定义TreeLoader 在ExtJS自己的TreeLoader中,当要实现从远程服务器端异步加载树节点信息的时候,都是通过请求服务器上的某一个URL来进行的,这个URL返回下面的信息。 假如我们是直接通过拉如DWR远程脚本引擎在客户端直接调用服务器的业务方法,直接跳过了WEB(不需要Struts、JSP或其它Web层的代码)这一层,这时我们没有URL,这时该怎么办呢?这就需要使用到自定义的TreeLoader,我们将在下一节中来详细了解。 任务和总结: 1. 完成讲义中的示例 2. 实现三种DataReader数据解析器 3. 总结:三种DataReader数据解析器的区别和适用场景

下载文档到电脑,查找使用更方便

文档的实际排版效果,会与网站的显示效果略有不同!!

需要 15 金币 [ 分享文档获得金币 ] 0 人已下载

下载文档