深入剖析ExtJS 2.2实现及应用连载(13):数据与列表的应用

2.5子页面

深入剖析ExtJS 2.2实现及应用连载  版权所有,谢绝转载  作者:彭仁夔 QQ546711211

上面的登陆和主页面已经是构成了一个整体。但是笔者认为作为演示整个Ext的功能不是还不够,麻雀的五脏还没有俱全呢,因为我们还没有演示ExtGrid和其Data功能,这是其非常重要的一个应用。

而且在上一节中的演示中,我们可能点击任何一个节点,都会生成一个默认的页面,但是通过addPanel来增加节点和页面的对应的函数还没有用上。就是连findPanel函数的正确性都没有能力去测试一下。

建立一个页面来进行一下这个工作是有必要的。这一节我们就通过显示所有公司列表的内容来建立这么一个页面。从功能来完整整个构建。在构建之前,我们得想到Company是一个类,我们一般采用默认的命名规则,还有它既然是整片内容,也要实现布局,所以我们就采用继承Panel类来实现它,其实很多内容的展现都会采用继承panel或其子类来实现其功能的。

代码清单2.16                                                MainingPanel代码

Morik.Office.CompanyPanel = function(config) {

Morik.Office.CompanyPanel.superclass.constructor.call(this, config);

    //加上其它功能 

}

Ext.extend(Morik.Office.CompanyPanel, Ext.Panel,{});

这是搭建整个类的架子,下面我们就要往这里添内容。对于Grid列表的实现,我们要分成两大步来作,第一步是如何去定义或取得列表的数据。第二步是如何去构建Grid列表组件。

2.5.1数据处理

  在使用Grid来进行列表,那首先得有数据可以用来列表。对于列表的数据,一般都是采用ExtStore来完成。Store把数据的请求分成三个部分,Proxy是用来进行本地数据和原始数据中间的一个代理,如果是远程Http的原始数据,它就要完成请求工作。不管怎么讲,对于不同的原始数据都可能通过Proxy来获取。

请求了原始数据之后,就要分析这些数据。Reader是把代理得来的数据进行分析,形成JavaScript的对象形式,如Json字符串的数据,如Xml的数据,这样都要解析成JavascriptJson对象的形式。

分析完成这些数据,那么就要提供一些方法来操作它们,这个任务是通过Store来完成的。Store是数据处理的对外接口,它内部统一了proxy,reader的方式,对外屏蔽了代理、分析数据。

下面我们就要定义表格的数据,这一节的代码(除jsp之外),都可以依次加在代码2.16CompanyPanel的构建函数内部。

   1、定义代理

 Ext提供的代理有三种,HttpProxy, MemoryProxyScriptTagProxyHttpProxy是通过http协议代理远程后台的原始数据,MemoryProxy是代理客户端本地的原始数据。ScriptTagProxy是代理跨域的远程原始数据。在这里我们采用从后台的Jsp文件中获取数据,因为它不是跨域的,所以我们采用HttpProxy

var proxy=new Ext.data.HttpProxy({url : 'company.jsp'});

其实我们也可以直接在Store(下面将介绍)中直接通过url配置项指定后台的文件地址来代理HttpProxy完成工作。不过采用构建代理器的好处是它能进行更多的请求时参数的配置工作。如上面,我们可以在加上method:get来指定请求的方式。

2、定义分析器

  分析器是对通过代理获得的原始数据进行解析,请求的数据有各种各样的格式,分析器是要这多样格式的数据解析成统一的格式。即两维表形式的数据格式。通用的数据格式有下三种:Xml,Json,ArrayXML是采用XML文本的方式来保存原始数据。而Json字符串的数据则是采用Json的格式来保存数据。Array是通过JS数组来保存的数据,它是客户端本地的数据,而Xml,Json一般是从远程请求。

这里的company.jsp生成的是Json数据如下:

<%@ page language="java" pageEncoding="UTF-8"%><%         out.println("{results:15,rows:[");

    out.println("{id:1,comNum:\"3301\",comName:\"南昌集电\",

comAddress:\"江西南昌市高新区火炬大道788\"}");

    out.println(",{id:2,comNum:\"3302\",comName:\"南昌中兴\",

comAddress:\"江西南昌市高新区火炬大道788\"}");

//类似数据,共15条,下面的数据省略。  

    out.println("]}");

    %>

这里生成Json形式的数据。下面我们就要通过JsonReader解析这些数据,因为它解析的结果是两维表的数据形式,对于两维表,我们得定义表的列字段,即表的列对应原始数据中列。如表中第1列对应字段名为comNum的列的数据是通过Record.create来完成的。

var recordType = new Ext.data.Record.create([

{name : "id",mapping : "id", type : "int"  },

 {name : "comNum",  mapping : " comNum ",type : "string"   },

{name : "comName", mapping : " comName ",type : "string"  },

{name : "comAddress", mapping : " comAddress ",type : "string"}]);

这里创建的是二维表的列和它与原始数据之间的关系。在create参数是一个集合数据,每个元素都是代表着二维表中的一列。其中name是代表着这个二维表当前列的名字。之后对于这一列的数据操作,就可以通过这个name和对应的行数来找到对应单元格的数据。mapping是建立这列和原始数据之间的映射关系,也就是对应原始数据中那个属性中,如第一条对应是原始数据中id,即所有的id指定的数据都会存放在这一列中。其实这里的mapping是可以省略的,因为它默认是采用和name中指定的名字来进行映射的。

对于type,是指定二维表中当前列的数据类型,把原始数据中属于该列的数据按指定的格式转换它。如果没有指定type就采用原始数据中的直接返回值。对于原始数据也是string而言,那么这里多了一个唯一的好处,它就是会把undefined转为空字符。指定类型还是好一点。

指定了二维表各个列的对应关系。那么接下来要做的是解析它,为什么Record.create创建的称为recordType,它就是创建原始数据的记录类型,即是数据的统一格式。但是它还有数据,这个数据是要通过JsonReader进行分析,并传到这个记录类型中去。

var reader = new Ext.data.JsonReader(

    {totalProperty : "results",  root : "rows",id : "id"},

 recordType);

所有的Reader都有两个参数,第一个参数是指定原始与记录类型对应关系。第二个参数是记录类型。在第一个参数中, totalProperty是用来指定原始数据中那个属性是用来指定这个需要转换的二维表的数据有多少行。在company.js中我们就指定了results:15root是指定需要转换数据的属性名,即然采用列表的形式,那么root映射的原始数据中属性名对应的数据应该是数组集合的形式。在这里rows中我们就指定了15条数据。recordType的记录类型就是对应是这个rows集合中数据。它把这个集合中的数据转化二维的形式,便于操作。

3Store统一它们

 Storeproxyreader统一起来,向那些需要数据的提供统一的数据操作接口。开发者只要获得store的引用就可以对数据进行操作。

var ds = new Ext.data.Store( {proxy:proxy,reader : reader});

Store的配置也很简单,一般都需要指定proxyreader,如果没有指定proxy,那么就得指url,它实质上也是proxy,只不过在store中内部构建而起的。对于store,我们还可以指定其的配置项来进行进一步的控制。详细内容在第5章中介绍。

接下要做的就是通过ds.load()来载入数据到二维表中。这样Grid才会有数据。ds.load()可以放在定义完成ds之后。

定义完成store,下一节中,将分析其Grid的应用。  

2.5.2 列表

在上一节中,我们定义了数据,这些数据是采用二维表的形式,但是那只是虚拟的数据表的形式,不直观,这一节我们通过Grid组件把它们的数据形式直观地表现在网页上。对于列表,我们首先也要定义表的列。

这个是通过ColumnModel来完成的,它主要是建立Store中二维表列和显示表的列的对应关系,对于要显示的表列,那么除了数据之后,还得控制外观,比如表列的宽度,比如表列中单元格的内容对应方式等。其实ColumnModel还要完成一些其它的操作,如列中的数据排序等。这里我们仅仅是简单地演示表列的定义,详细见第18章。

var cm = new Ext.grid.ColumnModel( {

    defaultSortable : true,  defaultWidth : 180,

    columns : [ { header : '编号',dataIndex : 'comNum'},

{header : '名称',dataIndex : 'comName' },

{header : '公司地址',width : 300,   dataIndex : 'comAddress' }]

    });

表列模式是要定义表的每一列,在这里我们通过defaultSortable defaultWidth指定每列缺省的的排序能力和宽度。接下来的columns就是定义每一列的具体的操作。其它中header是必不可以少的一部分,它是用来指明表的列头部分内容。dataIndex是建立Store和表当前列的对应关系,它就是recordType中指定的name。如果没有指定dataIndex,就会根据顺序号来找到Store中对应的列。如编号列在当前表是第1列,那么就找到Storeid列。È果显示表和数据表中的列是一一对应的,就可以省略它。

那么它们如何和Store联接起来呢,这个就GridPanel来完成的任务,ColumnModel作为是GridPanel的必要配置项传入(columns配置项可以看作其简化版本),而Store也要做为它的必要配置项传入。GridPanel在内部会建立它们之间的关系。

var grid = new Ext.grid.GridPanel( {

       cm : cm,

       store : ds,

       height :400,

       title : '公司列表'

    });

在这里,我们就定义了cmstore分别来指定其列和数据。现在我们可以运行一下,看看其显示的效果。但是什么都没有显示出来,是什么原因,数据定义了,也通过Load载入了,grid的列和数据也分别指定了。firebug的断点也显示grid是已经生成了。

这里就涉及到组件的渲染过程(即显示的问题)。如果我们对于组件(这里就是gridPanel)指定了renderToapplyTo 把当前组件渲染到指定的html元素中。在构建时就会自动去渲染该组件。如果配置中没有指定,我们可以通过组件的show来进行直接渲染到当前页面的body元素中或指定的元素之中。

如果也没有调用show的话,那么对于属于容器类(Panel及子类也属于)items中子组件在渲染类时就会嵌套渲染其中所有的子组件,我们的CompanyPanel又是属于这种情况,但是GridPanel仅仅是生成了,却没有成为CompanyPanel的子组件,也就是不会进行渲染。

在这里我们可以加上:this.add(grid);就可以完成自动的渲染工作。对于采用renderToapplyToshow方法一般都要指定其对应的htm元素,还要在html页面中(这里是main.html)中建立对应div标签。而通过容器类的自动渲染就不需要了。

现在就可以看到效果了,但是并不是尽人意。首先我们需要每次点击leftmenu中的公司管理的节点时,都会重新载入数据,对于想查看历史数据,则可以通过点击TabPanelTab就可以进行。

这个就是需要我们每一次在MainingPanelloadTab方法时,都要调用其子组件的dsload的方法,但是有的子组件中没有ds怎么办?不处理。我们要在loadTab方法最后面加上if (n.ds)  n.ds.load();来完成每次点击都会重载数据。

但是就CompanyPanel类而言,我们没有提供ds的属性,所以在copanyPanel类中构建函数最后处加上this.ds=ds;要把它的局部变量转换该对象的ds属性。这样就实现了每次点击都会重新载入数据。

但是这样还缺点,就是每次载入时,都没有提供正在载入,对于一个良好用户体验的系统,进行遮罩提示是很有必要。这里的grid也要加上它,使数据在载入时告诉用户稍等。加入遮罩提示,我们可以通过gridPanelloadMask的配置项。它可以调定为true采用默认的提示信息,还可以直接给出其提示信息。如下面代码:

       loadMask:{msg:'正在载入数据,请稍等...'},

但是这样的运行出现的结果是只有遮罩,而没有提示,因为它采用是当前Panelbwarp方式,我们一定要指定其宽高,高已经指定,加上width : 660,的配置项就可以了。现在就可以看到效果了。

2.6小结

在本章,通过了一个例子来轮廓地介绍Ext的应用和其功能。首先我们介绍了布局的使用,在登录页面和主页面中,我们用到border,column,formaccordion等布局。除了布局之外,在2.3中介绍了Form的方方面面的应用。在2.4中介绍了如何去继承扩展组件和如何使用树组件,2.5中我们介绍了datagrid两大部分。

这一章的内容对于初学者可能会有一些难度,但是只要跟着一步步去做,就能实现它的效果,至于内面的原理及相关的东西在学习完了这本书之后再回来看,就很清楚.

posted on 2008-12-13 10:17  彭仁夔  阅读(4945)  评论(8编辑  收藏  举报