【jQuery 分页】jQuery分页功能的实现

时间:2023-03-09 13:34:38
【jQuery  分页】jQuery分页功能的实现

自写的jQuery实现分页功能的分页组件:

功能效果如下:

【jQuery  分页】jQuery分页功能的实现

分页组件就是上图中的三部分, 分别放在表格上部  和下部 。

其中,

1》》》页面的代码如下:

product.jsp

其中引用bootstrap.css  和bootstrap .js是必须的

 <%@ page language="java" import="java.util.*" pageEncoding="utf-8" contentType="text/html; charset=UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<meta name="renderer" content="webkit|ie-comp|ie-stand">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no" />
<meta http-equiv="Cache-Control" content="no-siteapp" /> <link href="../css/H-ui.min.css" rel="stylesheet" type="text/css" />
<link href="../css/H-ui.admin.css" rel="stylesheet" type="text/css" />
<link href="../css/style.css" rel="stylesheet" type="text/css" />
<link href="../lib/Hui-iconfont/1.0.1/iconfont.css" rel="stylesheet" type="text/css" />
<link href="../css/bootstrap.min.css" rel="stylesheet" type="text/css" /> <title>产品列表</title>
<style type="text/css" >
.pageInfo{
display: inline;
}
</style>
</head>
<body> <nav class="breadcrumb" style="padding: 0px 1px 20px 0px;margin-bottom: 0px;"><i class="Hui-iconfont"></i> 首页 <span class="c-gray en">&gt;</span> 基因信息管理 <span class="c-gray en">&gt;</span> 产品列表 <a class="btn btn-success radius r mr-20" style="line-height:1.6em;margin-top:3px" href="javascript:location.replace(location.href);" title="刷新" ><i class="Hui-iconfont"></i></a></nav> <div class="pd-20">
<div class="text-c">
<select class="select" id="" name="" style="width:250px">
<option value="0">产品</option>
<option value="AccountInfo">基因型</option>
<option value="AdminInfo">关键字</option>
</select>
<button name="" id="" class="btn btn-success" type="submit"><i class="Hui-iconfont"></i> 查询</button>
</div>
</div>
<div class="cl pd-5 bg-1 bk-gray mt-20">
<span class="l"><a href="javascript:;" class="btn btn-danger radius"><i class="Hui-iconfont"></i> 批量删除</a>
<a class="btn btn-primary radius" href="javascript:;"><i class="Hui-iconfont"></i> 添加产品</a></span>
</div> <!-- 分页 + table 从这里开始 由于样式采用bootstrap,所以class样式尽量使用一致的 -->
<div class="container">
<!-- 分页的第一部分 开始 -->
<div class="row" style="margin: 20px 0px 5px 10px;">
<label class="pageInfo">每页显示 </label>
<select class="form-control pageInfo" style="width: 20%">
<option>5</option>
<option selected="selected">10</option>
<option>20</option>
<option>50</option>
<option>100</option>
</select>
<label class="pageInfo">条</label>
</div>
<!-- 分页的第一部分 结束 -->
<!-- table部分 开始 -->
<div class="row"><!-- 采用样式row 分成一层 一层 -->
<table class="table table-hover table-bordered table-bg">
<thead>
<tr class="text-c">
<th width="25"><input type="checkbox" id="ch1">全选</th>
<th width="80">产品名称</th>
<th width="280">操作</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
<!-- table 部分结束 -->
<!-- 分页 第二部分 开始 -->
<div class="row">
<!-- 第二部分左边部分开始 -->
<div class="pageInfo pull-left" style="position: relative;top: 32px; font-family: Times New Roman;">当前显示第<label class="startInfo"></label>条到第<label class="endInfo"></label> 条,总共<label class="totalInfo"></label>条</div>
<!-- 第二部分右边部分 开始 -->
<div class="pageInfo pull-right">
<nav >
<ul class="pagination">
<li>
<a href="#" aria-label="Previous" style="display: none">
<span aria-hidden="true">&laquo;</span>
</a>
</li>
<li class="active"><a href="#">1</a></li>
<li>
<a href="#" aria-label="Next">
<span aria-hidden="true">&raquo;</span>
</a>
</li>
</ul>
</nav>
</div>
</div>
<!-- 分页第二部分 结束 -->
</div> <script type="text/javascript" src="../lib/jquery/1.9.1/jquery.min.js"></script>
<script type="text/javascript" src="../lib/layer/1.9.3/layer.js"></script>
<script type="text/javascript" src="../lib/My97DatePicker/WdatePicker.js"></script>
<script type="text/javascript" src="../js/bootstrap.min.js"></script>
<script type="text/javascript" src="../lib/datatables/1.10.0/jquery.dataTables.min.js"></script>
<script type="text/javascript" src="../js/H-ui.js"></script>
<script type="text/javascript" src="../js/H-ui.admin.js"></script>
<script type="text/javascript" src="../js/pageSet.js"></script>
<script type="text/javascript" src="../js/geneinfo/product/product.js"></script>
</body>
</html>

2》》》分页组件的js文件

pageSet.js

 var page = {}; // 定义分页类
(// 这里用大括号将整个的类 包括【本类的属性定义】【本类的方法】 整体括起来,是让本类在页面加载的时候就运行 // tt这个类的字段定义
function() {
page.bindData;
page = function page(url, bindData) {
this.pageNo = 1; // 当前页 初始值为1
this.pageSize = 10; // 当前页显示多少条
this.startInfo = 1; // 开始条数
this.endInfo = 10; // 结束条数
this.totalPage = 0; // 总页数
this.totalInfo = 0; // 总条数
this.tempLi = "<li><a href='#'></a></li>"; // 用于添加页码处使用
this.url = url; // 用于不同页面的请求地址
this.result = null; // 用于可能仅需要正文数据时使用
this.bindData = bindData;
this.init();
return this;
} // 根据初始化的参数 bindData()绑定参数的方法 page初始化的对象 来请求后台,传回 新的page信息
page.prototype.pageSet = function() {
$.post(page.url, {
"pageNo" : page.pageNo,
"pageSize" : page.pageSize
}, function(data) {
result = null;
data = eval("(" + data + ")");
if (data != null && data != "" && data != undefined) {
page.pageNo = data.pageNum == 0 ? 1 : data.pageNum;
page.pageSize = data.pageSize == 0 ? page.pageSize : data.pageSize;
page.startInfo = data.pageNum == 0 ? 0 : (page.pageNo - 1) * page.pageSize + 1;
page.endInfo = page.startInfo + page.pageSize - 1;
page.endInfo = page.endInfo >= data.total ? data.total : page.endInfo;
page.totalPage = data.pages;
page.totalInfo = data.total;
page.result = data.list;
}
// 执行绑定参数的方法
bindData();
// 如果总页数 <=1 隐藏下一页
if (page.totalPage <= 1) {
$("a[aria-label='Next']").hide();
}
});
} // 设置分页组件的 一些信息 eq:总共多少条 显示第几条~第几条 动态显示页码
page.prototype.setValue = function() {
$("label.startInfo").text(page.startInfo); // 为此三个元素赋值
$("label.endInfo").text(page.endInfo);
$("label.totalInfo").text(page.totalInfo);
var temp = "";
if (page.totalPage != 0) { // 首先保证总页数不是0页
$(".pagination li").removeClass("active"); // 移除掉之前的 当前页面 页码按钮的
// 选中状态
if (page.totalPage <= 5
&& $(".pagination li").length != page.totalPage + 2) { // 【初始化总页数小于5页的情况】此处规定下面显示的页数就是5页 如果总页数<5则全部显示》》》$(".pagination li").length !=page.totalPage + 2保证不会重复叠加
for (var i = 0; i < page.totalPage - 1; i++) { // 总页数<5,则全部添加
temp += $(page.tempLi).find("a").text(i + 2).parent().prop("outerHTML"); // 为tempLi变量中的a标签添加页码数 然后找到a标签的父层
// 此时的它是Object类型,需要通过prop("outerHTML")这个属性,获取到HTML代码,这样才能用于追加进页面 【 原生JS DOM里有一个内置属性outerHTML】
}
page.cleanUp();
$(".pagination li").eq(1).after(temp); // 并将动态生成的页码按钮的HTML代码
// 添加到li的第二个之后
// 【这里是eq(1)第二个是因为(上一页)这个按钮虽然属性设为隐藏,但是依旧存在;而默认的还有一个第一页这个页码是存在的。所以是两个li,所以是eq(1)】
} else { // 否则,是总页数>5的
var absCon = Math.abs($(".pagination li").eq(3).text()- page.pageNo); // 先获取eq(3)也就是 中间位置的页码-当前页
// 【点击中间页码 靠后的页码按钮的情况】如果当前页>中间位置的页码数 && 中间位置的.length !=0 &&
// (除了最后一个页码li之外的的最后一个li的文本)也就是倒数第二个的文本!=总页数 【这里的判断条件就是
// 如果点击的是中间位置靠后的页码 eq:12345中的4或者5的话】 条件成立
if (page.pageNo > $(".pagination li").eq(3).text()
&& $(".pagination li").eq(3).length != 0
&& $(".pagination li:not(:last):last").text() != page.totalPage) {
absCon = page.totalPage - page.pageNo >= absCon ? absCon
: page.totalPage - page.pageNo; // 【当前页就是即将要显示的页码】如果
// 总页数-当前页>absCon
// 那么就给absCon原本的值,否则就将总页数-当前页的值赋值给absCon
for (var i = 0; i < absCon; i++) { // 此处absCon的作用:
// 点击中间位置靠后的页码数,可能即将显示的当前页
// 是最后一页了,那就不再添加新的页码出来了【eq:总共9页,即将显示的是第9页,那9这个页码之后就不再新增加页码了】
// 然后将新增加的页码添加在最后一个li【此处的最后一个li是下一页按钮】之前
// ;要添加的内容就是新生成的li的HTML文本 【eval($(".pagination
// li").eq($(".pagination li").length - 2).text())+1
// 这里使用eval()将其中的内容括起来是为了获取到的值直接和1相加】
$(".pagination li").last().before(
$(page.tempLi).find("a").text(
eval($(".pagination li").eq(
$(".pagination li").length - 2)
.text()) + 1).parent().prop(
"outerHTML"));
$(".pagination li").eq(1).remove(); // 并且在循环中始终删除eq(1)也就是前一页按钮之后的第一个页码
}
} else { // 【初始化 页数大于5页的情况】如果 当前页面上的li【包括上一页,下一页总共7个页码按钮】!=7个
// && 当前页面上的li个数 !=总页数+2 【此处的总页数是后台返回的总页数】
if ($(".pagination li").length != 7
&& $(".pagination li").length != page.totalPage + 2) {
for (var i = 0; i < 4; i++) {
temp += $(page.tempLi).find("a").text(i + 2)
.parent().prop("outerHTML");
}
$(".pagination li").eq(1).after(temp.toString());
// 【点击 中间页码靠前页码的情况】如果当前页<中间位置的页码 && 上一页按钮之后的页码按钮>=2
// 【即点击的中间页码按钮靠前的页码按钮】
} else if (page.pageNo < $(".pagination li").eq(3).text()
&& $(".pagination li").eq(1).text() >= 2) {
absCon = page.pageNo - 1 > absCon ? absCon
: page.pageNo - 1;
for (var i = 0; i < absCon; i++) {
$(".pagination li").first().after(
$(page.tempLi).find("a").text(
eval($(".pagination li").eq(1)
.text()) - 1).parent()
.prop("outerHTML"));
$(".pagination li").eq(
$(".pagination li").length - 2).remove(); // 靠后的页码按钮
// 【此处-2是将上一页
// 下一页两个按钮去掉】
}
} }
} //删除或者新增信息的时候,页码可能动态变化
if($(".pagination li:not(:last):last").text() > page.totalPage) {
$(".pagination li:not(:last):last").remove();
if(page.pageNo == page.totalPage) {
$("a[aria-label='Next']").hide();
}
if($(".pagination li:not(:first):first").text() > 1) {
$(".pagination li:first").after($(page.tempLi).find("a").text(parseInt($(".pagination li:not(:first):first").text()) - 1).parent().prop("outerHTML"));
}
} //上一页 下一页 的隐藏与显示
if($(".pagination li:not(:last):last").text() > page.pageNo) {
$("a[aria-label='Next']").show();
} else {
$("a[aria-label='Next']").hide();
} if($(".pagination li:not(:first):first").text() < page.pageNo) {
$("a[aria-label='Previous']").show();
} else {
$("a[aria-label='Previous']").hide();
} $(".pagination li:contains(" + page.pageNo + ")")
.addClass("active"); // 为 新的 当前页 页码按钮 添加 active选中状态
}
} // 初始化方法 页码的点击事件 上下页点击事件 每页显示多少条的 改变事件
page.prototype.init = function() {
$("a[aria-label='Previous']").click(function() {
$("a[aria-label='Next']").show();
if (page.pageNo == 2) {
$("a[aria-label='Previous']").hide();
} else {
$("a[aria-label='Previous']").show();
}
if (page.pageNo == 1) {
return;
}
page.pageNo--;
page.pageSet(bindData, page);
}); // 绑定 下一页 的点击事件
$("a[aria-label='Next']").click(function() {
$("a[aria-label='Previous']").show();
if (page.pageNo == page.totalPage - 1) {
$("a[aria-label='Next']").hide();
} else {
$("a[aria-label='Next']").show();
}
page.pageNo++;
page.pageSet(bindData, page);
}); // 上面的.click()绑定点击事件 和 下面的 $(document).on("click",".pagination
// li:gt(0):not(:last)",function(){});的区别在于:
// .click只能为页面现有的元素绑定点击事件,如果是动态生成的新的元素,是没有事件的
// 而$(document).on("click","指定的元素",function(){});方法则是将指定的事件绑定在document上,而新产生的元素如果符合指定的元素,那就触发此事件 // 为动态生成的 页码按钮 添加 点击事件
$(document).on("click", ".pagination li:gt(0):not(:last)", function() {
page.pageNo = $(this).text();
$("a[aria-label='Previous']").show();
$("a[aria-label='Next']").show();
if (page.pageNo == "1") {
$("a[aria-label='Previous']").hide();
}
if (page.pageNo == page.totalPage) {
$("a[aria-label='Next']").hide();
} page.pageSet(bindData, page);
}); // 为select 选择每页显示多少条 添加改变时间 【但是这不使用change而是使用input 是因为change对IE浏览器不支持】
$(".pageInfo").on(
"input",
function() {
page.pageSize = $(this).val();
page.pageNo = 1;
$("a[aria-label='Previous']").hide();
$(".pagination li:not(:first):not(:last)").remove();
// $(".pagination li:not(:first), .pagination
// li:not(:last)").remove();
$(".pagination li:first").after(
"<li class='active'><a href='#'>1</a></li>");
page.pageSet(bindData, page);
}); } /**
* 清除页码部分,回到初始化状态
*/
page.prototype.cleanUp = function() {
$("a[aria-label='Previous']").hide();
$("a[aria-label='Next']").show();
$(".pagination li:gt(0):not(:last)").remove();
$(".pagination li:eq(0)").after("<li><a href='#'>1</a></li>");
} })();

3》》》本页面的js中  需要提供数据的封装功能 bindDate()方法,【并且注意,任何页面发生变化的地方都需要调用分页的page.pageSet();方法,例如数据的增加,数据的删除,还有page对象初始化,页面初始化的时候就是这几个地方需要调用】

    3.1》》》product.js中的page对象初始化也就是在页面初始化的时候+删除操作的时候

 var indexProductAdd;//定义一个index作为产品添加弹出窗的layer打开返回值 ,用于关闭的时候使用
var indexProductUpdate; //定义一个index作为添加产品的弹出框的返回值
var product;
var page;
var bindData; $(document).ready( function () { /**
* 查询类型 【eq:产品:product 疾病:disease 基因:gene 】
*/
var queryType; /**
* 添加产品 页面
*/ $(".btn-primary").click( function(){
indexProductAdd = layer.open({
type: 2,
title: "添加产品",
content: 'productadd.htmls',
area: ['500px', '580px']
});
}); /**
* updateproduct.htmls 更新 产品信息
*/
$(document).on("click",".table-bordered tbody tr a[class='up']",function(){
product = $.parseJSON( $(this).parents('tr').find("input").eq(1).val());
$(this).parents('tr').find("input[type='checkbox']").prop("checked",true);//在点击更新按钮之后,勾选本行对应的checkbox
indexProductUpdate = layer.open({
type: 2,
title: "修改产品",
content: 'updateproduct.htmls',
area: ['500px', '580px'],
end : function(){
$(".table-bordered tbody :checked").attr("checked",false);
}
});
}); /**
* 封装数据 的方法 在本页面的js中,
*/
bindData = function bindData(){
var result = page.result;
$(".table-bordered tbody").empty();
if(result != "" && result != null && result != undefined) {
var temp = "";
$.each(result, function(index, item) {
//JSON.stringify(item) 对象转化字符串
temp += "<tr class='text-c'><td><input type='checkbox' value='"+item.productId+"'><input type='hidden' value='"+JSON.stringify(item)+"'/></td><td>"+item.productName+"</td><td><a href='disease.htmls?productId="+item.productId+"' class='check'>【查看疾病信息】</a><a href='JavaScript:void(0)' class='up'>【更新】</a></td></tr>";
});
$(".table-bordered tbody").append(temp);
}
page.setValue();
} /**
* 实例化一个分页组件的 对象
*/
page = new page("queryAllProduct2.htmls", bindData);
page.pageSet(); /**
* 批量删除
*/
$(".btn-danger").click(function(){
var productId = [];
$(".table-bordered tbody :checked").each(function(index,item){ //注意:checked前面需要空格
productId.push(item.value); //数组中添加数据 需要push()
}); if(productId.length == 0){
layer.msg('请选择至少一条记录!', {
icon: 3,
time: 2000 //2秒关闭(如果不配置,默认是3秒)
}, function(){
//do something
});
return;
}else{
$.post("productDelete.htmls?productId="+productId, function(data){
if(data){
layer.msg('删除成功!', {
icon: 1,
time: 2000 //2秒关闭(如果不配置,默认是3秒)
}, function(){
//do something
}); // page.cleanUp();
if($(".table-bordered tbody :checked").length == $(".table-bordered tbody tr").length && page.pageNo>1){//若本页全部删除
page.pageNo--;
}
page.pageSet();
}else{
layer.msg('删除失败!', {
icon: 2,
time: 2000 //2秒关闭(如果不配置,默认是3秒)
}, function(){
//do something
});
}
$(".table-hover thead :checked").attr("checked",false);
return;
});
}
}); } );

    3.2》》》productAdd.js中添加一条数据完成后

 $(document).ready( function () {

     //为添加产品的表单加验证效果
$('#form-product-add').bootstrapValidator();
//$('#form-product-add').data('bootstrapValidator').validate(); //提交按钮是sumbit
//$('#form-product-add').data('bootstrapValidator').isValid(); //提交按钮是button
/**
* 添加产品的按钮
*/
$("#pAdd").click(function(){
$('#form-product-add').bootstrapValidator('validate');//为表单的添加按钮 添加一个绑定表单的方法
var productName = $("input[name='productName']").val();
var productCre = $("textarea[name='productCre']").val();
var temp;
if(productName !="" ){
$.ajax({url:"productAdd.htmls",
type:"post",
data:{
"productName" : productName,
"productCre" : productCre
},
success:function(data){ if(data != null){
parent.page.pageSet();
}
// var index = parent.layer.getFrameIndex(window.name); 可以用这个获取当前要关闭的layer ,也可以使用parent.indexProductAdd 获取在父层定义的那个layer。open()的弹窗
parent.layer.close(parent.indexProductAdd); //获取到layer的弹出窗 关闭它
}}); }
return false;//页面的表达提交使用submit,然后又对这个提交按钮绑定一个点击事件,使用ajax来和后台进行交互,这个时候如果不return false;会导致ajax提交一次,submit提交一次,这样的错误不容易找出来,会表现出来:ajax执行成功但是时而会进回调函数,时而不会进入回调函数,
}); /**
* 全选按钮的 全选功能
*/
$('table th input:checkbox').on('click' , function(){
var that = this;
$(this).closest('table').find('tr > td:first-child input:checkbox')
.each(function(){
this.checked = that.checked;
$(this).closest('tr').toggleClass('selected');
});
});
} );

4》》》controller服务器中的处理方法

@Controller
@RequestMapping("geneInfo")
public class GeneInfoController {

 /**
* 分页查询---查询所有产品
* @param model
* @return
*/
@RequestMapping("/queryAllProduct2")
@ResponseBody
public PageInfo<Product> queryAllProduct2(ModelMap model, int pageNo, int pageSize){
Criteria criteria = getCurrentSession().createCriteria(Product.class);
return productService.findQuery(criteria ,pageNo , pageSize );
}

5》》》Dao的实现层 的分页实现

 @Override
public PageInfo<T> findQuery(Criteria criteria, int pageNo, int pageSize) {
try {
Assert.isTrue(pageNo >= 1, "pageNO should start from 1");
//拆分order by子句
Field field = CriteriaImpl.class.getDeclaredField("orderEntries");
field.setAccessible(true);
List<?> orderEntrys = (List<?>) field.get(criteria);
field.set(criteria, new ArrayList());
//统计总数
long totalCount = countAll(criteria);
criteria.setProjection(null);
//统计完了再把order by子句加上 这样保证了sql语句不会出错
field.set(criteria, orderEntrys);
List<T> list = findPage(criteria, pageNo, pageSize);
if (totalCount < 1) {
return new PageInfo<T>();
}
PageInfo<T> page = new PageInfo<T>();
page.setPageNum(pageNo);
page.setTotal(totalCount);
page.setPages((int) (totalCount / pageSize == 0 ? totalCount / pageSize : totalCount / pageSize + 1));
page.setPageSize(pageSize);
page.setList(list);
return page;
} catch (Exception e) {
// TODO: handle exception
throw new QueryException("查询出错!");
} }

其中主要的思想 就是 将分页组件 分离出来,仅作分页处理。而数据的封装则是在不同的页面进行不同的封装实现。然后封装数据的方法作为参数传递给分页对象。