高端ajax分页
admin 发布于:2012-6-26 22:09:00
阅读:loading
ajax分页很简单,具体怎么简单这个就不同详细说了,要想写的灵活,通用,以前的那个实现就显得逊色了。
其实ajax分页对我来讲是小菜了,现在为何又关注这个?实在是因为现在改的项目里面有ajax分页的实现,觉得里面几个地方确实是比JSP分页要好。
注意:前端ajax分页略过,这里指使用ajax+json的方式使用所有前端处理分页的方式,在页面上用JS控制分页,只关注这个的话,绕道吧。
ajax分页优点:
第一:在列表页面有,可能会有很多查询条件,一部分查询条件都是从数据库里面查询出来的,类似基础数据,那么在进入页面之前需要先加载,每翻一页害得加载,换成无刷新分页则就只需要加载一次即可。
第二:在按条件查询的时候,需要按条件显示翻页数据,比如,下拉框改选中的选中,单选框,文本框等等(去年听到一个名词叫:“回显”,是一个意思),就不需要页面讲值传来传去的,ajax分页的直接将查询条件获取到后处理,不需要再保存返并返回做数据回显用了,为什么呢?
第三:无刷新当然要比刷新效果要好了。
第四:此处省略一些字。
ajax分页实现:
现在一个jquery的ajax请求返回的数据方式多了,见得多的实现方式是利用ajax+json实现的,前台发送ajax请求,后来不变,只是Dao在处理数据的时候,将返回回来的分页列表对象转换成相应的json数据,这个转换的组件此处略过,返回到前台页面,页面再根据json中的各个属性来做相应的处理。
其实想想就知道,将json数据显示到页面中,常见的做法是动态创建 <tr><td>的形式来创建,既然是这种JS动态创建的,那么开发人员不能直接操作分页表格对象,即操作list数据,假设列表属性中有图片,全选什么的,都还需要做特殊处理。我这里想说的是既如此那么对象中所有的数据到要在后台处理好,比如,User对象有个sex属性,页面需要做国际化,那么数据库中存储的肯定是 user.sex类型的text,需要处理的肯定是在action层中迭代数据,然后将值拿到,再 getText 处理,如果是在页面上那么<s:text />,s标签直接就搞定了,等等,再比如说:管理员权限的用户列表,用户有状态:可用、禁用,对于禁用的用户拥有删除的权限,如果这些判断放在后台,我想有这层限制,使用这个组件的人肯定用的也不爽,要么又得改了,要么果断排斥,这是一个比较疼的问题。
/*********************************************************************/
这里关于ajax分页在项目中的应用谈两点。第一点小规模的改动将项目中的jsp分页改造成ajax分页;第二点在以后的项目中使用ajax分页,并且分页的数据,例如显示的分页数据,还是使用<c:forEach />这种后台语言实现,同原始JSP分页实现,页面上可以有后台代码的判断逻辑。
关于小规模的改动将jsp分页修改成ajax分页,这里的实现到最后,只是单纯的将JSP分页转换成ajax的,页面上面无刷新,但是出于对程序的负责态度,性能并没有减少,单纯的无刷新而已,这种效果优点就是代码改动非常小,实现了无刷新,不足:性能没优化到,白搭。这种方式实现提供如下思路:第一:在显示分页列表的时候,页面改怎么写不变,分页的那一部分数据,换成ajax加载,即加载ajax加载的地址是分页的第一页的数据,即给个页号或者相关查询条件去能显示分页显示数据的页面,既然是ajax加载的,也就是相当于JS代码,则把加载的源文件数据获取,然后再将获取分页数据的源文件(鼠标右键——查看源文件),将源文件获取到,用正则也好,将关于分页的那一段数据获取到,然后在显示在页面上,即,有一个js函数,改函数传递一个参数,返回根据这个参数加载的地址的源文件,那么传递一个显示第N页的分页地址,改函数直接将返回第N页的源文件数据,再解析这段源文件,然后显示在页面上,第N+1页也是如此,到此为止,算是完事儿了。至于根据一个地址返回一个地址解析后的源文件的JS技术实现,我所知道有两种形式:1、jquery的laod函数,可以将地址返回的源文件,追加到某个对象里头;2、dwr中的WebContext对象forwardToString函数。
/*********************************************************************/
现在说的是一种项目中可以运用的ajax分页实现,可能说东西都不难,就是思路不一样,这个思路也是见到项目中的ajax分页之后想了几天想到的,虽然都是ajax分页,但我觉得这个优点就是灵活性强,上手容易,基本不需要关注别的代码。
效果图:
基于这种方式的实现,必须要解决的问题:
每次翻页的时候,页面无刷新,且页面上面的数据不能用json格式的处理,因为要把后台列表的逻辑判断交给开发使用者。
想ajax实现分页并且业务逻辑用JSP代码控制,而非JS来控制,则需要处理一下,算了这个方面就不赘述了,如果有心实现的话,必然会遇到这个问题的,等有人遇到了再议。
把这里问题处理好了,基本上就完事儿了。怎么解决这个问题呢,我的实现是采用jquery.form plugin,该插件是什么我这里不说,因为前面的几篇日志有关于这个的介绍。页面大致布局如下:
直接上代码吧。
/****************************************************************************************************************************************/
1、web.xml,配置分页的servlet
<servlet>
<servlet-name>person</servlet-name>
<servlet-class>com.demo.page.servlet.PersonServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>person</servlet-name>
<url-pattern>/person.do</url-pattern>
</servlet-mapping>
2、PersonServlet.java
package com.demo.page.servlet;
import java.io.IOException;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.demo.page.PageFinder;
import com.demo.page.Person;
public class PersonServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("PersonServlet.doGet()");
String encoding = "utf-8";
request.setCharacterEncoding(encoding);
response.setCharacterEncoding(encoding);
response.setContentType("text/html;charset=" + encoding);
String method = request.getParameter("method");
if("page".equals(method)){
String pageNo = request.getParameter("page");
if(pageNo == null){
pageNo = "1";
}
List<Person> dataList = new com.demo.page.Data().getDataList(Integer.parseInt(pageNo));
PageFinder pageFinder = new PageFinder(Integer.parseInt(pageNo), 10, 100, dataList);
request.setAttribute("pageFinder", pageFinder);
request.getRequestDispatcher("/demo/p1table.jsp").forward(request, response);
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
this.doGet(req, resp);
}
}
3、Data.java是我的Dao类,就是生成一些数据并存储在集合中,并返回,来模拟代替我们的从数据库中查询
package com.demo.page;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.UUID;
/**
* @author cdd
* 构造100条数据,用于分页
*/
public class Data {
private static final int pageSize = 10;
private static final int totalPage = 10;
public final static List<Person> dataList = new ArrayList<Person>();
static{
for(int i=1;i<=pageSize * totalPage;i++){
dataList.add(new Person(i,UUID.randomUUID().toString(),new Random().nextBoolean() ? "男" : "女"));
}
}
public List<Person> getDataList(int pageNo){
List<Person> list = new ArrayList<Person>();
int start = (pageNo-1) * pageSize;
int end = (pageNo-1) * pageSize + pageSize >= dataList.size() ? dataList.size() : (pageNo-1) * pageSize + pageSize;
for(int i=start;i<end;i++){
list.add(dataList.get(i));
}
return list;
}
public static void main(String[] args) {
List<Person> dataList = new Data().getDataList(11);
for (Person person : dataList) {
System.out.println(person.getId() + "," + person.getName() + "," + person.getSex());
}
}
}
4、PageFinder.java该类只是一个对于分页数据的简单封装,将需要分页的数据传递给他,由它来控制分页
package com.demo.page;
public class PageFinder {
public static final int DEFAULT_PAGE_SIZE = 10;
/**
* 分页大小,即每页最多能显示的记录条数
*/
private int pageSize;
/**
* 分页的总记录数
*/
private int totalRows;
/**
*当前页数
*/
private int page;
/**
* 上一页
*/
private int prePage;
/**
* 下一页
*/
private int nextPage;
/**
* 最后一页
*/
private int lastPage;
private Object data;
public PageFinder(int page, int pageSize, int totalRows) {
this.setPage(page);
this.setPageSize(pageSize);
this.setTotalRows(totalRows);
}
public PageFinder(int page, int pageSize, int totalRows,Object data) {
this.setPage(page);
this.setPageSize(pageSize);
this.setTotalRows(totalRows);
this.setData(data);
}
public int getLastPage() {
return (int) Math.round(Math.ceil((double) this.getTotalRows()
/ (double) this.pageSize));
}
public void setLastPage(int lastPage) {
this.lastPage = lastPage;
}
public int getTotalRows() {
return totalRows;
}
public void setTotalRows(int totalRows) {
this.totalRows = totalRows;
}
public int getPage() {
return page;
}
public void setPage(int page) {
this.page = page;
}
public int getNextPage() {
return this.getPage() + 1 >= this.getLastPage() ? this.getLastPage()
: (page + 1);
}
public void setNextPage(int nextPage) {
this.nextPage = nextPage;
}
public int getPrePage() {
return (page - 1 >= 1) ? (page - 1) : 1;
}
public void setPrePage(int prePage) {
this.prePage = prePage;
}
public int getPageSize() {
return pageSize;
}
public void setPageSize(int pageSize) {
this.pageSize = pageSize;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
}
5、显示分页的主页面,暂时称为 personManager.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>ajax分页实例</title>
<script type="text/javascript" src="${pageContext.request.contextPath }/js/jquery-1.5.2.min.js"></script>
<script type="text/javascript" src="${pageContext.request.contextPath }/js/jquery.form.js"></script>
<script type="text/javascript" src="${pageContext.request.contextPath }/js/jquery.page.js"></script>
<script type="text/javascript">
$(function(){
$("#mySubmitForm").ajaxSubmitForm();
});
</script>
</head>
<body>
<center>
<form action="${pageContext.request.contextPath }/person.do?method=page" method="post" id="mySubmitForm">
姓名:<input type="text" name="name" />
性别:<input type="text" name="sex" />
<input type="submit" value="查询" />
</form>
<h4>ajax分页,非返回json形式,<font color="red">代码跟非ajax分页一样灵活</font></h4>
<div id="showPager"></div>
</center>
</body>
</html>
6、分页数据迭代页面,暂时称为 personList.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<table>
<tr>
<td>编号</td>
<td>姓名</td>
<td>性别</td>
<td>操作</td>
</tr>
<tbody>
<c:forEach items="${pageFinder.data }" var="data">
<tr>
<td>${data.id }</td>
<td>${data.name }</td>
<td>${data.sex }</td>
<td>
<c:if test="${data.id % 2 == 0 }">
<a href="?id=${data.id }">修改</a>
</c:if>
</td>
</tr>
</c:forEach>
</tbody>
<tr>
<td colspan="3" align="center" >
<c:import url="../common/page.jsp?formId=mySubmitForm"></c:import>
</td>
</tr>
</table>
7、js,暂时称为jquery.page.js
/**
* jquery form plugin插件简单封装
* 在少量改动原有JSP分页代码的基础上,将分页转换成ajax形式的,非返回json格式数据的形式,与JSP分页一样灵活
*/
(function($) {
$.fn.ajaxSubmitForm = function(options) {
var thisElement = $(this);
//当每次点击查询按钮时,查询的数据显示第一页
thisElement.find(":submit").bind("click",function(){
$("#queryPage").val("1");
});
var defaults = {
target : '#responseoutput',
type : 'post',
dataType : 'html',
beforeSubmit : function(formData, jqForm, options){
return true;
},
success : function(responseText, statusText, xhr, $form){
$("#" + options.showPagerId).html("");
$("#" + options.showPagerId).append(responseText);
},
resetForm : false,
timeout : 10000,
error:function(tip){
alert("出错了:" + tip.status);
},
showPagerId:'showPager'
};
var options = $.extend(defaults, options);
this.each( function() {
var output = document.getElementById("responseoutput");
if (output == null) {
var putdiv = document.createElement("div");
putdiv.id = "responseoutput";
putdiv.style.display = "none";
document.body.appendChild(putdiv);
}
$(thisElement).ajaxForm(options);
$(thisElement).trigger("submit");
});
};
})(jQuery);
8、分页的按钮栏封装,主要是控制上一页、下一页,暂时称为page.jsp
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<c:if test="${not empty pageFinder.data}">
<div align="center">
<a href="javascript:void(0);" onclick="goFirstPage()">首页</a>
<a href="javascript:void(0);" onclick="goPrePage()">上一页</a>
<a href="javascript:void(0);" onclick="goNextPage()">下一页</a>
<a href="javascript:void(0);" onclick="goLastPage()">末页</a>
第${pageFinder.page }页 共 ${pageFinder.lastPage } 页,
每页 ${pageFinder.pageSize } 项
</div>
<script type="text/javascript">
var page = "${pageFinder.page }";
var lastPage = "${pageFinder.lastPage}";
//首页
function goFirstPage(){
if(page != "1"){
createQueryPageHidden("1");
}
}
//上一页
function goPrePage(){
if(parseInt(page) - 1 >= 1){
createQueryPageHidden(parseInt(page) - 1);
}
}
//下一页
function goNextPage(){
if(parseInt(page) + 1 <= parseInt(lastPage)){
createQueryPageHidden(parseInt(page) + 1);
}
}
//末页
function goLastPage(){
if(parseInt(page) != parseInt(lastPage)){
createQueryPageHidden(lastPage);
}
}
function createQueryPageHidden(value){
var queryFormId = "${param.formId}";
var queryPage = document.getElementById("queryPage");
if(queryPage == null){
$("#" + queryFormId).append("<input type='hidden' name='page' id='queryPage' value='" + value + "' />");
}else{
$("#queryPage").val(value);
}
$("#" + queryFormId).trigger("submit");
}
</script>
</c:if>
9、把javabean类给忘了,这里贴上代码补充下
package com.demo.page;
public class Person {
private int id;//编号
private String name;//名称
private String sex;//性别
public Person(){
}
public Person(int id,String name,String sex){
this.id = id;
this.name = name;
this.sex = sex;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
}
/****************************************************************************************************************************************/
代码就这些了,没什么难度,最值得说的就是非 js + json,非js迭代table数据,而是jsp代码迭代集合,如果不知所云,两个可能,1、我没说清楚,2、你没这么思考过,不知道实现这个东西的常规实现。
现在贴上效果图吧,无图无真相。
日志说完了,高端在哪里呢,我觉得就是第6段代码,这段代码看似很平常,其实。。。?
补充一点:
今天上午给一些功能的查询列表页面添加 “重置”按钮的功能,普通jsp查询分页,每次提交后,都刷新页面,然后再将该回显的文本框回显,下拉框选中,此时的重置按钮,重置的状态时onload页面之后,js代码执行完之后的一个状态,而非未点击查询按钮时的状态,即初始化进入页面的一个状态,文本框为空白,下拉框选中的是 “请选择”,或者“全部”,需要特殊处理,而ajax方式的查询,就能狠方便的解决这种问题,直接一个rest按钮。
点赞