学校软件工程让写课程设计(其实就是自选语言做个项目),感觉都是重复的东西就没有很认真的去写内容,更加注意写一些之前没有用过的东西。
因为一直都使用TP框架来写PHP,TP又自带分页类,想到这里就想试试写一个异步分页,于是昨天用了4个小时思考带调试写来出来...
思路:
异步分页和同步分页最直观的一点就是切换数据页不用刷新页面,然后用Jquery动态的来创建一些html元素并给与相应的显示规则,结合后台请求来切换表格数据。切换表格数据不属于分页内容,因此这里只探讨分页空间本身。
实现:
接下来大致说一下我写的这个分页类
1 function Page(count,listRow,showPageCount,obj,getData){ 2 var o = {};//分页对象 3 o.nowPage = 1;//当前为第几页 4 o.listRow = listRow;//一页显示多少条数据 5 o.getData = getData;//取数据的回调函数 6 o.obj = obj;//制定在那个元素后面显示(Jquery对象) 7 o.count = count;//数据总数 8 //总页数 9 o.totalPage = o.count% o.listRow == 0? parseInt(o.count/ o.listRow) : parseInt(o.count/ o.listRow+1); 10 //显示多少个分页按钮 11 o.showPageCount = o.showPageCount < o.totalPage? o.showPageCount : o.totalPage; 12 o.first = 1;//第一个显示的分页按钮是多少 13 //最后一个显示的分页按钮是多少 14 o.last = o.totalPage > showPageCount?showPageCount: o.totalPage;
使用JS工厂创建对象,先说说参数列表:
参数 | 描述 |
count | 数据总数 |
listRow | 每页显示的数据数量 |
showPageCount | 显示多少个分页按钮 |
obj | 在哪个对象后创建分页控件 |
getData | 点击按钮事件后的回调函数,用于得到数据并修改界面UI |
对象属性:
属性 | 描述 |
nowPage | 当前是第几页 |
listRow | 一页能显示多少条数据 |
getData | 点击按钮事件后的回调函数,用于得到数据并修改界面UI |
obj | 在哪个对象后创建分页控件 |
count | 数据总数 |
totalPage | 一共有多少页 |
showPageCount | 显示多少个分页按钮 |
first | 分页控件从第几页开始显示 |
last | 分页控件显示到第几页 |
这些属性中,
totalPage是计算出来的,它等于数据总数除以每页的数据量,如果不能整除还需要加1。
showPageCount是计算出来的,它如果比totalPage还大,值就为totalPage,否则就等于传进来的参数。
first是分页控件中最左边的按钮的值,初始为1。
last是分页控件中最左边的值,初始为showPageCount。
在分页控件不断地变化中,其实真正改变的只是first,last和nowPage这三个属性。
下面一起来看一下分页控件的产生过程
1 /* 2 * 创建分页控件 3 */ 4 o.createPage = function() 5 { 6 //拼接分页控件 7 var html = "<div class = 'page-div'><div class = 'my-page'>"; 8 for(var i = 0 ; i < o.showPageCount ; i++) 9 { 10 //拼接每一个分页数组按钮,并为其设置id 11 html += "<a href='#' id=page"+(i+1)+" class = 'page-item each-page'>"+(i+1)+"</a>"; 12 } 13 //拼接下一页按钮 14 html += "<a href='#' class = 'page-item next-page'>>></a></div></div>"; 15 //在指定的对象后创建控件 16 o.obj.after(html); 17 $("#page1").css("background-color","gray"); 18 //调用获取数据的回调函数 19 o.getData(o.nowPage, o.listRow); 20 }
从代码中可以看出,Page对象有一个createPage方法,它通过组装html来实现创建分页控件,同时,第16行是在指定的jquery对象后面添加该元素,17行是让默认第一个按钮为被选中的加深背景颜色,最后调用回调函数getData来获得分页控件所控制的第一次的数据。
注意getData中有两个参数,传的分别是当前的页数和每一页多少行数据,相信用过分页的人都知道,这两个参数到后台是为了用limit来限制数据库查询的。
创建后接下来我们要为创建的元素来绑定事件,代码如下:
1 /* 2 * 为控件绑定点击事件 3 */ 4 o.bindAction = function() 5 { 6 $(".pre-page").click(function(){ 7 o.nowPage = parseInt(o.nowPage) - 1; 8 if(o.nowPage < (o.totalPage-o.showPageCount/2) && o.first > 1) 9 { 10 o.first = parseInt(o.first) - 1; 11 o.last = parseInt(o.last) - 1; 12 } 13 o.updatePage(); 14 o.updateColor($(this),$("#page"+ o.nowPage)); 15 o.getData(o.nowPage, o.listRow); 16 }); 17 18 $(".each-page").click(function(){ 19 o.nowPage = $(this).text(); 20 if(o.nowPage >= o.showPageCount/2+1 && o.nowPage <= (o.totalPage - o.showPageCount/2)) 21 { 22 if(o.showPageCount%2 == 0) 23 { 24 o.first = parseInt(o.nowPage)-parseInt(o.showPageCount/2-1); 25 o.last = parseInt(o.nowPage)+parseInt(o.showPageCount/2); 26 } 27 else 28 { 29 o.first = parseInt(o.nowPage)-parseInt(o.showPageCount/2); 30 o.last = parseInt(o.nowPage)+parseInt(o.showPageCount/2); 31 } 32 } 33 else if(o.nowPage < o.showPageCount/2) 34 { 35 o.first = 1; 36 o.last = o.showPageCount; 37 } 38 else if(o.nowPage > (o.totalPage - o.showPageCount/2)) 39 { 40 o.first = parseInt(o.totalPage) - parseInt(o.showPageCount)+1; 41 o.last = parseInt(o.totalPage); 42 } 43 o.updatePage(); 44 o.updateColor($(this),$("#page"+ o.nowPage)); 45 o.getData(o.nowPage, o.listRow); 46 }); 47 48 $(".next-page").click(function(){ 49 o.nowPage = parseInt(o.nowPage) + 1; 50 if(o.last < o.totalPage && o.nowPage > o.showPageCount/2+1) 51 { 52 o.first = parseInt(o.first) + 1; 53 o.last = parseInt(o.last) + 1; 54 } 55 o.updatePage(); 56 o.updateColor($(this),$("#page"+ o.nowPage)); 57 o.getData(o.nowPage, o.listRow); 58 }); 59 }
其实这里主要是为三类按钮绑定事件,分别是pre-page、each-page和next-page,对应的按钮分别是,前一页,中间的数字按钮和后一页。
首先要先为大家说明一点的是,分页的居中问题,用过分页的我们都应该知道,分页如果不是在选择的页数不是最靠近第一页或者靠近最后一页,那么当前的选择项应该是默认在中间的。这样说可能大家也不是很清楚,我拿baidu的分页给大家举例说明:
首先我们先选中第一页来看效果:
可以看到选择第一页的时候是没有前一页的按钮的。
接下来我们点击第二页看看:
可以看到,上一页出现了,但是2这个按钮并没有居中显示,因为它的左边只有1并且1已经显示出来了。
点击7看看结果:
可以看大,7居中显示了,因为它的左边即显示不到1,右边也显示不到16(共16页)
我们在点击15看看效果:
可以看出来该结果一共是16页的,所以当点击15的时候因为右边最大显示的是16,所以15也没有居中显示
同样的当我们点击16的时候下一页的按钮会消失。
相信说道这里,大家对于分页已经有一个简单的认识了,那么接下来,我们看看该如何去判断这些问题。
其实前面也说了,判断这些界限问题,主要就是根据first、last和nowPage来改变分页状态的,nowPage是我们直接改变的,first和last是根据nowPage而间接进行改变的。
第6~16行处理的是点击前一页时所触发的事件。首先让当前页数-1,正常来讲此时我们应该让firstPage和lastPage都-1来保证能够显示到更前面的一些页面。但是我们需要考虑到上面说的居中问题,所以我们需要先进行一个判断,如果当前的页面是小于 totalPage-showPageCount/2(这样判断就可以保证在最右边如果接近了最大页数可以不再去改变first和last的值),同时也要保证,first是大于1的,如果等于1了肯定就不会在first和last的值肯定就不会改变了,那么就可以是first和last-1,属性修改之后,第13~15行分别是重新生成分页元素,修改被选中项的背景,然后重新请求数据。(这三个方法后面会讲到)
第18~46行处理的是点击每一个分页按钮所触发的事件。首先让当前页数为所点击的按钮的页数,然后需要判断nowPage,先判断如果
nowPage >= o.showPageCount/2+1 && o.nowPage <= (o.totalPage - o.showPageCount/2)
也就是说如果是nowPage即不靠近左边的1,也不靠近最大页数,那么就应该让当前选中的页居中显示。所以first和last就应该分别设置到nowPage两端,在设置之前还要先判断,如果按钮个数是偶数个的话,是不可能让被选中的按钮在正中间的,所以需要设置
o.first = parseInt(o.nowPage)-parseInt(o.showPageCount/2-1);
o.last = parseInt(o.nowPage)+parseInt(o.showPageCount/2);
如果是奇数个就可以在正中间,那么就设置为
o.first = parseInt(o.nowPage)-parseInt(o.showPageCount/2);
o.last = parseInt(o.nowPage)+parseInt(o.showPageCount/2);
接下来就需要判断,如果nowPage是小于showPageCount/2的,也就是说是靠近1的,此时first和last就应该保持不变,first就是1,last就是showPageCount的值。
如果nowPage是大于totalPage-showPageCount/2的,也就是说是靠近totalPage的,此时first就是totalPage-showPageCount/2+1,last就是totalPage。
然后和上面一样调用重新生成分页元素,修改被选中项的背景和重新请求数据的方法。
第48~57行和第一类思路是一样的,只不过判断的是last的临界,这里就不再螯述了。
下面看另外一个方法:
1 /* 2 * 更新分页控件 3 */ 4 o.updatePage = function() 5 { 6 //根据当前页判断重新拼接分页控件 7 var html = ""; 8 if(o.nowPage != 1) 9 { 10 html += "<a href='#' class = 'page-item pre-page'><<</a>"; 11 } 12 for(var i = o.first ; i <= o.last ; i++) 13 { 14 html += "<a href='#' id=page"+i+" class = 'page-item each-page'>"+i+"</a>"; 15 } 16 if(o.nowPage != o.totalPage) 17 { 18 html+="<a href='#' class = 'page-item next-page'>>></a>"; 19 } 20 $(".my-page").html(html); 21 o.bindAction(); 22 }
该方法是更新分页控件的方法,根据nowPage、first和last来更新,
首先判断如果nowPage不是第一页,那么就加上‘上一页’的按钮。
然后根据first和last来循环添加中间的数字按钮。
接下来如果nowPage不是最后一页,那么就加上'下一页'的按钮。
最后为新生成的元素绑定事件。
1 /** 2 * 显示分页空间 3 */ 4 o.show = function() 5 { 6 o.delete(); 7 o.createPage(); 8 o.bindAction(); 9 } 10 /* 11 * 更新控件颜色 12 */ 13 o.updateColor = function(self,obj) 14 { 15 //将所有的分页按钮背景颜色设为白色 16 self.parent().find('a').css("background-color","white"); 17 //将选中的按钮背景设为灰色 18 obj.css("background-color","gray"); 19 } 20 /* 21 * 删除控件 22 */ 23 o.delete = function() 24 { 25 $(".page-div").html(" "); 26 }
最后三个方法放在一起说了。
首先说下更新控件颜色,传的参数一个是触发事件的对象,另一个是需要设置为选中状态的对象,分别改变他们的颜色。
显示分页控件很简单,实际上就是删除原有的分页,创建新的分页最后绑定事件。写该方法是因为有时候我们操作数据会改变数据的个数,此时我们就需要重新创建一个分页对象,就需要调用该方法。
说了这么多接下来就说说用法
用法很简单
1 var searchTable = function(nowPage,listRows) 2 { 3 var url = $("#search").attr("url"); 4 var startTime = $("#startTime").val(); 5 var endTime = $("#endTime").val(); 6 var realname = $("#realname").val(); 7 var mode = 0; 8 if($("#user_mode").attr("value") == 1) 9 mode = 1; 10 else 11 mode = 2; 12 $.ajax({ 13 type:"post", 14 url:url, 15 data:{"startTime":startTime,"endTime":endTime,"real_name":realname,"mode":mode,"now_page":nowPage,"list_rows":listRows}, 16 success:function(data) 17 { 18 if(data == 0) 19 { 20 alert("暂无符合要求数据"); 21 } 22 else 23 { 24 data = JSON.parse(data); 25 removeDataRow(); 26 addNewData(data); 27 } 28 }, 29 error:function() 30 { 31 alert("查询失败"); 32 } 33 }); 34 }
首先定义了取数据的回调函数。
1 var url = $("#data-count").attr("value"); 2 $.ajax({ 3 url: url, 4 type:"post", 5 success:function(result) 6 { 7 var page = new Page(result,1,10,$("#data-table"),searchTable); 8 page.show(); 9 } 10 , 11 error:function() 12 { 13 alert("路径错误"); 14 } 15 });
然后得到数据总数,并创建分页即可,实际上就
var page = new Page(result,1,10,$("#data-table"),initTable);
page.show();
这两句是我们分页类有关的代码,剩下的都是为我们的参数所准备的代码。
这里说一下,如果我们想要动态的修改表格数据,是需要重新生成分页类的,也就是说需要重新得到正确的参数来构造分页对象。
最后附上源码供大家参考(样式表大家可以定制自己喜欢的,这里我就不再传了):
1 /** 2 * Created by gy on 15/4/19. 3 */ 4 5 function Page(count,listRow,showPageCount,obj,getData){ 6 var o = {};//分页对象 7 o.nowPage = 1;//当前为第几页 8 o.listRow = listRow;//一页显示多少条数据 9 o.getData = getData;//取数据的回调函数 10 o.obj = obj;//制定在那个元素后面显示(Jquery对象) 11 o.count = count;//数据总数 12 //总页数 13 o.totalPage = o.count% o.listRow == 0? parseInt(o.count/ o.listRow) : parseInt(o.count/ o.listRow+1); 14 //显示多少个分页按钮 15 o.showPageCount = o.showPageCount < o.totalPage? o.showPageCount : o.totalPage; 16 o.first = 1;//第一个显示的分页按钮是多少 17 //最后一个显示的分页按钮是多少 18 o.last = o.totalPage > showPageCount?showPageCount: o.totalPage; 19 20 /** 21 * 显示分页空间 22 */ 23 o.show = function() 24 { 25 o.delete(); 26 o.createPage(); 27 o.bindAction(); 28 } 29 30 /* 31 * 创建分页控件 32 */ 33 o.createPage = function() 34 { 35 //拼接分页控件 36 var html = "<div class = 'page-div'><div class = 'my-page'>"; 37 for(var i = 0 ; i < o.showPageCount ; i++) 38 { 39 //拼接每一个分页数组按钮,并为其设置id 40 html += "<a href='#' id=page"+(i+1)+" class = 'page-item each-page'>"+(i+1)+"</a>"; 41 } 42 //拼接下一页按钮 43 html += "<a href='#' class = 'page-item next-page'>>></a></div></div>"; 44 //在指定的对象后创建控件 45 o.obj.after(html); 46 $("#page1").css("background-color","gray"); 47 //调用获取数据的回调函数 48 o.getData(o.nowPage, o.listRow); 49 } 50 /* 51 * 更新分页控件 52 */ 53 o.updatePage = function() 54 { 55 //根据当前页判断重新拼接分页控件 56 var html = ""; 57 if(o.nowPage != 1) 58 { 59 html += "<a href='#' class = 'page-item pre-page'><<</a>"; 60 } 61 for(var i = o.first ; i <= o.last ; i++) 62 { 63 html += "<a href='#' id=page"+i+" class = 'page-item each-page'>"+i+"</a>"; 64 } 65 if(o.nowPage != o.totalPage) 66 { 67 html+="<a href='#' class = 'page-item next-page'>>></a>"; 68 } 69 $(".my-page").html(html); 70 o.bindAction(); 71 } 72 /* 73 * 更新控件颜色 74 */ 75 o.updateColor = function(self,obj) 76 { 77 //将所有的分页按钮背景颜色设为白色 78 self.parent().find('a').css("background-color","white"); 79 //将选中的按钮背景设为灰色 80 obj.css("background-color","gray"); 81 } 82 /* 83 * 删除控件 84 */ 85 o.delete = function() 86 { 87 $(".page-div").html(" "); 88 } 89 /* 90 * 为控件绑定点击事件 91 */ 92 o.bindAction = function() 93 { 94 $(".pre-page").click(function(){ 95 o.nowPage = parseInt(o.nowPage) - 1; 96 if(o.nowPage < (o.totalPage-o.showPageCount/2) && o.first > 1) 97 { 98 o.first = parseInt(o.first) - 1; 99 o.last = parseInt(o.last) - 1; 100 } 101 o.updatePage(); 102 o.updateColor($(this),$("#page"+ o.nowPage)); 103 o.getData(o.nowPage, o.listRow); 104 }); 105 106 $(".each-page").click(function(){ 107 o.nowPage = $(this).text(); 108 if(o.nowPage >= o.showPageCount/2+1 && o.nowPage <= (o.totalPage - o.showPageCount/2)) 109 { 110 if(o.showPageCount%2 == 0) 111 { 112 o.first = parseInt(o.nowPage)-parseInt(o.showPageCount/2-1); 113 o.last = parseInt(o.nowPage)+parseInt(o.showPageCount/2); 114 } 115 else 116 { 117 o.first = parseInt(o.nowPage)-parseInt(o.showPageCount/2); 118 o.last = parseInt(o.nowPage)+parseInt(o.showPageCount/2); 119 } 120 } 121 else if(o.nowPage < o.showPageCount/2) 122 { 123 o.first = 1; 124 o.last = o.showPageCount; 125 } 126 else if(o.nowPage > (o.totalPage - o.showPageCount/2)) 127 { 128 o.first = parseInt(o.totalPage) - parseInt(o.showPageCount)+1; 129 o.last = parseInt(o.totalPage); 130 } 131 o.updatePage(); 132 o.updateColor($(this),$("#page"+ o.nowPage)); 133 o.getData(o.nowPage, o.listRow); 134 }); 135 136 $(".next-page").click(function(){ 137 o.nowPage = parseInt(o.nowPage) + 1; 138 if(o.last < o.totalPage && o.nowPage > o.showPageCount/2+1) 139 { 140 o.first = parseInt(o.first) + 1; 141 o.last = parseInt(o.last) + 1; 142 } 143 o.updatePage(); 144 o.updateColor($(this),$("#page"+ o.nowPage)); 145 o.getData(o.nowPage, o.listRow); 146 }); 147 } 148 return o; 149 }