关键词
Ext,Ext.toolbar.paging
环境说明
开发环境:Eclipse Indigo
浏览器环境:Chrome
问题描述
在使用表格展示大量数据时,由于页面性能受限,通常使用分页功能逐页展示数据。
Ext中,Ext.toolbar.paging组件实现表格数据的分页显示,但是在测试过程中发现,若将最后一页的全部数据一次性删除,表格页面将没有任何数据显示(而此时后台实际是有数据的)。如下图:
![](https://img-my.csdn.net/uploads/201210/14/1350173081_3938.jpg)
初始首页,可以看到总共有3590条数据,共36个分页
删除最后一页后的问题页面,页面跳转按钮灰化,总页数、当前页数、记录条数等信息均显示为0
问题详述
定义用户的store如下,设定每页展示100条数据,使用proxy从后台servlet获取json格式的返回数据,返回的人员信息存放在”personArray”,返回的总记录条数存放在”totalCount”。
Ext.create('ExamPlatform.datamodel.PeopleM'); // 必须要先创建一次,否则store无法找到对应的model
var personInfoStore = Ext.create('Ext.data.Store', {
pageSize: 100,
autoDestroy: true,
model: 'ExamPlatform.datamodel.PeopleM',
proxy: {
type: 'ajax',
url: '/senhwa/queryPersonInfoServlet',
reader: {
type: 'json',
root: 'personArray', // 存放当前返回的数据
totalProperty : 'totalCount' //存放总共的记录数
}
}
Servlet中根据前台传送的参数 start和limit来返回对应的数据信息。这两个参数由Ext自动封装,start即起始记录的序号,limit即在store中定义的pageSize。
//获取limit和start参数
Integer limit = 50;
Integer start = 0;
try
{
limit = Integer.valueOf(request.getParameter("limit"));
start = Integer.valueOf(request.getParameter("start"));
} catch (NumberFormatException e1)
{
e1.printStackTrace();
}
try
{
PrintWriter out = response.getWriter();
List<PersonBean> personBeanList = PersonDAO.queryPersons();
int totalCount = personBeanList.size();
//判断末尾记录的序号
int end = CommonUtil.floor((start + limit), totalCount);
JSONArray array = JSONArray.fromObject(personBeanList.subList(start, end));
String jsonArray = array.toString();
String retJson = "{\"totalCount\":\"" + totalCount + "\",\"personArray\":" + jsonArray + "}";
out.write(retJson);
out.close();
}
catch (PersonDbException e)
{
e.printStackTrace();
}
catch (IOException e)
{
e.printStackTrace();
}
这里插一句,通过测试可以发现,Ext.toolbar.paging组件初始传给后台的[start,limit]为[0,100],点击next后传给后台[100,100],以此类推。由于总记录数不一定等于总页数×每页展示记录条数,所以在截取列表数据前,需要先比较start+limit与totalCount的大小,取其小者。
下面两张图分别是初始的第一页和第二页的数据,注意总页数是36页,总记录条数是3590条,当前第101条数据为“韩波”。
回到首页,将首页的100条数据全部选中并删除
可以看到序号1的记录正式原序号101的韩波,此时总记录条数变更为3490,总页数变更为35页,但是当前页号依然为1。
删除数据后,personInfoStore再次load数据
PersonInfoDwr.removePersonById(jsonStr, function()
{
//刷新列表
personInfoStore.load();
});
由此可以推测,传递给后台的[start,limit]依然是[0,100],即当前页号不变(依然为1),起始记录序号不变(依然为0)。
首先需要说明的是,针对一个列表中的数据进行删除,后面的数据自动补位,这样的处理符合习惯的。
让我们先查看一下最后一页(35)和最后第二页(34)的数据。
![](https://img-my.csdn.net/uploads/201210/14/1350175470_7422.jpg)
![](https://img-my.csdn.net/uploads/201210/14/1350175475_1210.jpg)
想象一下,当把最后一页的数据全部删除后,页面会展示什么数据?
·是否会像删除首页一样展示后续的数据?不可能了,因为后面已经没有数据了。
·不展示任何数据?可以理解。
·展示前一页的数据?这个是最符合习惯的,删除了最后一页,原来的最后第二页就应该展示到最后一页的地方。
那么我们来删除最后一页数据,看看会是什么效果。
![](https://img-my.csdn.net/uploads/201210/14/1350175502_7028.jpg)
如图所示,删除后没有数据显示,且当前页,总页数均显示为0,总记录数为0。页面跳转按钮灰化不可用。
通俗点说,这个页面不可用了!
为什么会出现这种情况?
首先,我们来查看之前操作传递给后台的数据如下:
| [start,limit,total] |
进入首页 | [0,100,3590] |
删除首页全部数据 | [0,100,3490] |
进入最后一页 | [3400,100,3490] |
删除最后一页全部数据 | [3400,100,3400] |
注意最后一行的start和total是相等的,即此时,截取到的列表将是空的。这也就是为什么删除后页面会没有数据展示。
但是为什么页面按钮会灰化呢?
查看Ext.toolbar.paging的源码可以看到,当页面发现数据为空时,将这些按钮设置不可用了。
count = me.store.getCount();
isEmpty = count === 0;
if (!isEmpty) {
pageData = me.getPageData();
currPage = pageData.currentPage;
pageCount = pageData.pageCount;
afterText = Ext.String.format(me.afterPageText, isNaN(pageCount) ? 1 : pageCount);
} else {
currPage = 0;
pageCount = 0;
afterText = Ext.String.format(me.afterPageText, 0);
}
Ext.suspendLayouts();
me.child('#afterTextItem').setText(afterText);
me.child('#inputItem').setDisabled(isEmpty).setValue(currPage);
me.child('#first').setDisabled(currPage === 1 || isEmpty); //为空则不可用
me.child('#prev').setDisabled(currPage === 1 || isEmpty); //为空则不可用
me.child('#next').setDisabled(currPage === pageCount || isEmpty); //为空则不可用
me.child('#last').setDisabled(currPage === pageCount || isEmpty); //为空则不可用
me.child('#refresh').enable();
me.updateInfo();
Ext.resumeLayouts(true);
这种处理其实是正确的,即初始表格为空时,不能使用这些按钮。
但是在这里,这样的处理就显然不妥了,因为页面直接不可用了,即使刷新页面也无济于事。
问题其实还是出在删除最后一页全部数据后,传递给后台的[3400,100,3400],倘若此时可以传递给后台[3300,100,3400],则可以解决当前的问题。
是否可以在sevlet中优化算法,当发现截取到的列表将为空时,自动返回最后一个limit长度的数据?结论是不可以!因为以上面的例子来说,删除第35页的数据后,sevlet会返回第34页的数据给页面,但是页面不知道后台返回给它的是第34页的数据,所以页面的编号依然是从3401开始,实际应该是3301开始。即序号和数据会不对应。
由于[start,limit]是Ext框架封装传递的,我们无法在页面去修改。
而经过走读paging.js发现,store有一个currentPage的属性,所以最后采用的方法就是在删除数据前,判断满足条件的时候,主动向前翻一页。
//--------------------修正currentPage数值-----------------------------------------------
//•这里的处理目的在于解决将最后一页全删除后,Ext默认的当前页(currentPage)值不变化,造成加载到store中的数据为空
//•当删除的数据不是最后一页时,currentPage不需要变化,可以直接加载到后面的数据,store不为空
//•但是当删除最后一页的数据时,若currentPage不变化,由于后面没有数据,会造成store为空,
//在Paging.js中会将当前页,总页等一起设置为0,造成表格不可用
//•当删除的即是最后一页,也是第一页时(即所有数据都展示在一页上)时,也不需要处理。
var totalCount = personInfoStore.getTotalCount(); // 所有的记录数,不单单是当前页展示的数据
var pageSize = personInfoStore.pageSize; // 一页上面展示的记录条数
var curPage = personInfoStore.currentPage; // 当前页码
var fromRecord = ((curPage - 1) * pageSize) + 1; // 当前页展示的起始记录号
var toRecord = Math.min(curPage * pageSize, totalCount); // 当前页展示的结尾记录号
var totalOnCurPage = toRecord - fromRecord + 1; // 当前页展示的记录条数
var totalPageCount = Math.ceil(totalCount / pageSize); // 总的页数
var delCount = length; // 删除的记录条数
//若当前页是最后一页,且不是仅有的一页,且删除的记录数是当前页上的所有记录数
if (curPage === totalPageCount && totalPageCount != 1 && delCount === totalOnCurPage)
{
personInfoStore.currentPage--;
}
//----------------------------------------------------------------------------------------------------
再次进行验证,删除第34页后,正确展示第33页的内容
后记
这样修改后,这个表格的功能就比较完善了,但是从实现上来看,下一个表格依然会有这样的问题,最好的办法当然是修改paging.js的源码,但同时也会造成后续更换新版本Ext的兼容问题,各有利弊吧。