闲话部分
最近闲着实在无聊,就做了点小东西练练手,由于原来一直在用AspNetPager进行分页,而且也进行了深度的定制与原有系统整合的也不错,不过毕竟是用别人的,想着看自己能试着做出来不能,后台的分页插件已经有比较成熟的了,那就自己试着写一个前台分页吧。
话不多说,先上效果图:
优点与缺点
来说说优缺点吧,首先AspNetPager是后台分页控件,所以在向客户端回传HTML文档之前生成HTML阶段 就会把分页代码生成完毕,然后回传,而JS是前端代码,就是HTML文档在服务器组织完毕往客户端传送完毕之后才登上舞台。基于上述的区别,很容易总结出下面的优缺点:
优点:
1,轻量级,引入JS即可,十分方便部署与使用。
2,与后台程序语言无关,可以在任何语言平台上使用。
3,减少服务器负担,减少传输成本,加快响应速度,改善用户体验。
4,前端代码没有被编译,方便维护和管理。
缺点:
1,不支持SEO优化。
2,需要单独编写接口。
基本思路
1,我们需要通过一些参数如:记录总条数(itemCount)、每页条数(pageSize)来计算总共可以分的页数(pageCount),itemCount需要通过请求数据来获取,而pageCoun则需要通过用户来指定。
2,我们需要知道当前是在第几页(currPage)。当页面首次加载的时候默认为1,用户也可以指定默认加载时处在第几页上。当翻页时就会获得一个新的currPage。
3,有了这些我们似乎是可以开始工作了,首页 尾页很好解决,首页页码永远为1,而尾页页码永远为pageCount,上一页 下一页也可以解决,上一页为 currPage-1 ,下一页为 currPage+1。似乎很完美,不过不要忘了,上一页页码为currPage-1只能是 在currPage>1的时候,而下一页页码为currPage+1则只能是在currPage<pageCount的时候,我想你一定知道为什么,所以在这里要判断一下。
4,通过currPage和pageSize,我们可以很轻松的计算出当前显示的记录为第几条~第几条,前面也获取到了pageCount,pageSize等数据,因此可以拼接字符串,来显示分页信息
信息显示例如: 共12条 第1/4页 第1~3条 3条/页
5,重头戏来了,对于中间页码部分的处理。简单处理的话很好办,从1到pageCount依次排列,似乎就可以了,但是不要忘了,假如你这个列表有几十页甚至上百页,那这样排列显然不够优雅,那么我们需要另外一个参数,那就是中间显示页码的个数(showPageCount),当页码很多的时候,最多只显示 2×showPageCount+1个页码。你一定会问,为什么是 2×showPageCount+1,而不是showPageCount。原因是我这里为了判断方便,showPageCount的含义为,当前页面左右两边出现的页码个数。
例如:总共有10页,当前页为5,showPageCount为2,
那么页码则显示为: 首页 上一页 3 4 5 6 7 下一页 尾页
意外情况:如果左边或者右边显示不够showPageCount的页码数量,为了保持页码显示量是一定的,则会从另外一侧补全。
例如:总共10也,当前页面为2,showPageCount为4,左侧只有1个页面可以显示,则从右侧补全,
页码显示为: 首页 上一页 1 2 3 4 5 6 7 8 9 下一页 尾页
6,再在最后设置一个 Input 和 A 标签用作转到指定页面功能。
7,到此为止,我们只需要把上面的各个步骤 分别拼接字符串 输出到页面上就OK了,但是,还有一个重要话题没有讨论,目前为止,我们只是实现了分页的结构,但是功能似乎还没有实现。实现功能有两种方式:
(1),给页码标签的 href 属性绑定对应的链接,后面跟参数如 href="Article.aspx?page=2" 点击之后带上页码参数2 去请求第二页的信息。我们在后台程序通过Request到page的值,给Repeater控件做相应的绑定也好,输出字符串也好,都可以实现功能。
(2),添加 onclick 属性,并绑定函数,通过函数做 ajax 请求,通过响应的函数(可以是键值对,也可以是HTML字符串),来给替换当前页面上的列表,产生新的列表,同时分页的当前页也需要更换成对应的当前页,完成之后效果实现。
第一种很简单,在拼接字符串的时候,顺带这把 href 属性写了就完事,这里不做过多叙述,关键说第二种,由于采用了ajax 在翻页的时候做请求,拿到响应数据,改写列表容器,既然如此,那么我们页面首次加载获取pageCount的时候,也可以顺便把列表给绑定了。简单总结起来大致流程如下:
A:页面加载——收集请求参数和查询条件(currPage为1),ajax请求,拿到响应信息(至少包括 itemCount 和 列表信息),通过回调函数,用itemCount 计算分页的各项参数 生成分页,通过列表信息,生成列表,完成初次加载。
B:翻页事件——再次收集求情和查询条件(currPage为当前页码),ajax请求,拿到响应信息(至少包括 itemCount 和 列表信息),通过回调函数,用itemCount 计算分页的各项参数 拼接字符串改写分页容器内容,通过列表信息,改写列表容器内容,完成初次加载。
我们可以直观的发现,A事件和B事件,流程基本一致,唯一的区别就是 currPage的值不同,因此我们可以做一个类似于递归的方法(不算严格意义上的递归),我们写一个 Load() 函数来用作 列表和分页的首次加载,在容器值被改写过之后,需要给 页码的 onclick 事件绑定函数,此时我们绑用本身这个Load()函数,所以每次点击后仍然绑定的是Load()方法。这样一段代码,就可以在两个事件中重复使用了。
8,关于传参,刚才我们一直提到 手机请求参数和查询条件,例如:容器ID,列表所属分类ID,每页条数,URL格式等等。 那么我们究竟如何把参数传递到方法中去?想实现目的,以下几种方式都可以。
A:声明全局变量,在函数中调用,但是这种方式会造成大量的变量冗余,同时 Load()函数需要 传入大量的参数,如:Load(agrA,agrB , agrC , agrD , agrE , agrF ... ),不可取。
B : 传入Json字符串,通过键值对的方式传入参数,这种方法,虽说只有一个参数,但是在编写的时候过于繁琐,而且无法指定默认值,或者可选项,需要在JS中重新判断,不可取。
C : 如果说上面两个都PASS掉了,那么你一定知道接下来要做什么了,没错!JavaScript是一门面向对象的语言,虽然经常被人们忽略,但是他是可以使用对象和面向对象的一些编程方式的,因此我们可以建立分页的实体类,然后每次调用的时候,new() 出来一个新的对象,这样既可以保证同一个页面有多个分页的时候互不冲突,同时又可以优雅地指定我们的属性值,还可以通过类似于构造函数的方式进行默认值的初始化。
调用方式
引入jquery、ruguoPager和css:
1 <script src="js/jquery-1.11.1.min.js"></script> 2 <script src="js/ruguoPager-1.0.js"></script> 3 <link rel="stylesheet" href="css/ruguoPager.css">
编写html结构指定好ID:
<div class="ctn"> <div class="news" name="pager1"> <ul class="list" id="news_ul"></ul> <div class="box_height_1000px"></div> <div class="ruguoPager_red" id="pager1"></div> </div> </div>
在HTML页面上加入script标签 指定对象参数 进行分页
1 <script> 2 var pager = new ruguoPager(); 3 pager.pagerType="ajax"; 4 pager.objName="pager"; 5 pager.pagerID="pager1"; 6 pager.listID="news_ul"; 7 pager.toPoint="pager1" 8 pager.showPageSize=4; 9 pager.pageSize=3; 10 pager.currPage=1; 11 pager.typeID=63; 12 pager.pagerUrl="news/list_{ruguo:pageNum}.html"; 13 pager.itemStr="<li><a href='news/detail_{ruguo:id}.html'>{ruguo:title}</a>[{ruguo:datetime}]</li>"; 14 pager.ajaxUrl="ajax/getArticleList.ashx"; 15 ruguoPagerLoad(pager); 16 </script>
参数列表(参数名,参数含义,可选值,必须)
pagerType | 初始化类型 | 'ajax' or ' url' | |
objName | 对象名 | string | * |
pagerID | 分页容器ID | string | * |
listID | 列表容器ID | string | - |
currPage | 当前页 | int | |
pageSize | 每页条数 | int | |
itemCount | 记录总条数 | int | |
showPageSize | 显示页码数 | string | |
pagerUrl | 分页路径格式 | string | - |
typeID | 列表类别ID | int | |
titLen | 列表标题字数 | int | |
itemStr | 列表标题格式 | string | |
ajaxUrl | ajax请求地址 | string | * |
toPoint | 锚点标记 | string | |
isShowFirst | 是否显示首页按钮 | 'always' , 'auto' , 'none' | |
isShowPreviousPage | 是否显示上一页按钮 | 'always' , 'auto' , 'none' | |
isShowNextPage | 是否显示下一页按钮 | 'always' , 'auto' , 'none' | |
isShowLastPage | 是否显示尾页按钮 | 'always' , 'auto' , 'none' | |
isShowPages | 是否显示页码按钮 | 'always' , 'auto_0' , 'auto_1' , 'none' | |
isShowGo | 是否显示跳转 | 'always' , 'auto' , 'none' |
总结
在编写插件的过程中,遇到了很多实际的问题,并一个一个的加以解决,得到了不少心得,在这里总结一下。
1,类的使用
在写Javascript的时候,尤其是在Jquery被广泛使用知乎,我们往往会在页面中罗列一个接一个的函数, 但是有时候我们尝试着使用一下类,会使得代码变得更加优雅。在写这个插件之前,只知道JS可以写类,实例化对象,但是究竟怎么用,却从来没试过,甚至怎么定义一个类都不知道。通过本例,初步了解了JS中类的基本使用方式。
2,函数的重载
在解决 Load() 函数重用问题上,我想使用重载,但是根据自己的猜想,试了一下没有成功,经过查资料发现正确的使用方式。在C#中我们知道,方法可以重载,要求方法名相同,返回类型或者形参类型、数量不同。然而针对于JS来说,是没有重载一说的,因为JS是若类型语言,在调用方法的时候,根本没有参数类型以及返回类型一说。虽然如此,好在参数个数还是可以检测到的,所以根据这一特点,可以进行模拟重载,但是注意并非真正重载。
3,全局变量
在写插件时候,第一次实例化的对象,并把对象的各个属性通过AJAX传递,拿到了响应信息,完成了分页和列表的首次加载。当点击分页时候,需要再次执行同样的操作,因此需要再次进行实例化对象,这样一来方法就无法复用,意味着,页面上每多一个分页,就需要copy一份js用作不同的 在点击分页时候的实例化。所以我就在想,点击分页事件时候的对象,与第一次的对象不一样的仅仅只是当前页码而已,所以通过对象本身包含对象名的方式,在绑定分页事件方法时,把对象名当作参数放在了Load()方法中,并多了一个当前页参数,通过模拟重载 顺利完成Load()方法的复用。虽然JS没有非常严格的访问级别,但是我想写在文档流中的变量应该都是全局变量,在初次实例化时候的对象同样也是,所以绑定分页事件方法中的参数 应该是可以调用到 全局对象的,结果证明我的猜想完全正确。
4,ajax分页用户体验
通过ajax分页时候会有一个问题,那就是点击分页之后,由于页面并不刷新或者跳转,而是直接修改了页面容器的内容,所以页面会保持在列表最下方不动,每次点击完分页,需要手动把网页拨回到最顶部,然后再慢慢往下翻着看,很麻烦,所以我做了一个本地描点,在初次实例化的时候需要传锚点ID,点击之后,返回到锚点处。
效果类似于腾讯新闻列表的效果: http://news.qq.com/top_index.shtml
5,jquery绑定事件传参
在写插件过程中,起初用到了需要往jquery绑定事件中传参,由于习惯了使用 例如 $("a").click(function(){ alert("hello world"); });这样的绑定方式,所以如何往click事件所执行的方法中传入参数一时间十分苦恼,后来经过查询,知道了可以使用 这样的方式进行传参:$("a").bind("click",{myValue:hello world},function(event){ alert(event.data.myValue) }); ,虽然后来有了更好的方式,无需传参了,但是也算是一个不小的收获吧。
6,当json遇上HTML
json是我们网上常用的传递数据的格式,而且js可以很轻松的解析,但是由于json遇到html中的 尖括号(< >)会出现问题,无法正确返回,因此,我们需要响应数据的时候进行HTML编码,在回调函数中,对拿到的编码后的字符串进行反编码。另外顺带提一下,在使用eval()解析数据的时候最好里面再套上一个"("+data+")",原因是json中的大括号会影响js的结构。
存在的问题
1,代码重用部分,其实并没有把url与ajax的方式完全区分开,由于当使用url的时候,初次加载列表和 总页数 可以通过后台绑定出来,因此在点击分页的时候,就无需再次请求数据,仅仅进行前台的计算即可,可以减少一次请求。
2,代码写的比较乱,大伙凑合着看吧。
3,本人才疏学浅,写代码纯属业余兴趣爱好,还望跟各位大神多多学习,存在的问题或者是更好的解决方案,还请不吝赐教,帮助我完善插件,网上成熟的插件有很多,本人献丑不敢说分享劳动成果工,只能说在学习中遇到的问题拿来给暂时还没有遇到的人,少走一些弯路,同时满足一下自己小小的成就感,仅此而已。
代码与文章都是博主辛苦一点一点码出来的,请尊重博主辛勤劳动,欢迎转载,转载请注明出处,更多交流请关注 D调码农的笔记簿http://www.cnblogs.com/webconfig
最后放出下载地址
相关文档下载: http://files.cnblogs.com/webconfig/ruguoPager.rar