关于本站
1、基于Django+Bootstrap开发
2、主要发表本人的技术原创博客
3、本站于 2015-12-01 开始建站
之前利用Django的Paginator分页器简单弄了分页功能,具体可以看我的网站搭建(第3天) Django分页器这篇文章。
这篇文章已经重新书写过了,之前写得比较糟糕,我自己都看不下去了。
随着发表的博文越来越多,会导致页码越来越多。页码显示的区域占用的空间也会越来越长。假如有20几页,30几页的页码都显示出来。那简直太惨不忍睹了,所以考虑优化一下。现在效果如下:
目前见得比较多的分页优化显示方式有三种:
1、"1 ... 5 6 7 8 ... 10" 用省略号表示隐藏中间部分的页码
2、"6 7 8 9 10 11 12 13 14 15" 连续显示多个页码,随当前页码变动页码范围(这种方式搜索引擎用得比较多)
3、下拉框选择页码(这个操作不直观,不选用这种)
博文的页码不会太多,所以我考虑采用第1种方式,再加上一个跳转页功能即可。
由于之前把分页功能写在helper文件夹中,封装成一个通用的方法(见我的网站搭建(第3天) Django分页器)。所以只需要改动这个方法,返回一个新的页码列表给html模版使用即可。
进一步分析一下。假如一共有8个页码,显示当前页上下两页和首尾的页码。罗列以下几种情况:
1、当前页是第1页
1 2 ... 8
2、当前页是第2页
1 2 3 ... 8
3、当前页是第4页
1 ... 3 4 5 ... 8
4、当前页是第7页
1 ... 6 7 8
5、当前页是第8页
1 ... 7 8
看上去似乎没问题,仔细分析,里面有些细节还是不够好。
当前页是第1页和第2页只是少了第3页没显示,当前页是第7页和第8页也是同样情况。这种情况可以考虑如果当前页是首尾的时候,多显示一页出来,让用户可选择的范围大一点。
另外当前页是第4页的时候,第一个省略号其实没什么意义,只是省略了一个页码。这个省略号同样也占用了一定空间,还不如把那个页码显示处理。
整理优化结果如下:
1、当前页是第1页
1 2 3 ... 8
2、当前页是第2页
1 2 3 ... 8
3、当前页是第4页
1 2 3 4 5 ... 8
4、当前页是第7页
1 ... 6 7 8
5、当前页是第8页
1 ... 6 7 8
大致分析清楚之后,开始写代码。要生成这种页码列表也有好几种方式。笨一点的方法就是判断当前页和首尾页码对比。我试了一下,挺麻烦的,要实现我上面优化的结果要判断很多种情况。最后改成下面的代码,直接对list处理。
通用的分页代码如下:
#coding:utf-8 from django.core.paginator import Paginator from django.conf import settings def getPages(request,objectlist): """get the paginator""" currentPage = request.GET.get('page', 1) paginator = Paginator(objectlist,settings.EACHPAGE_NUMBER) objectlist = paginator.page(currentPage) page_range = [] current = objectlist.number #当前页码 page_all = paginator.num_pages #总页数 mid_pages = 3 #中间段显示的页码数 page_goto = 1 #默认跳转的页码 #获取优化显示的页码列表 if page_all <= 2 + mid_pages: #页码数少于6页就无需分析哪些地方需要隐藏 page_range = paginator.page_range else: #添加应该显示的页码 page_range += [1, page_all] page_range += [current-1, current, current+1] #若当前页是头尾,范围拓展多1页 if current == 1 or current == page_all: page_range += [current+2, current-2] #去掉超出范围的页码 page_range = filter(lambda x: x>=1 and x<=page_all, page_range) #排序去重 page_range = sorted(list(set(page_range))) #查漏补缺 #从第2个开始遍历,查看页码间隔,若间隔为0则是连续的 #若间隔为1则补上页码;间隔超过1,则补上省略号 t = 1 for i in range(len(page_range)-1): step = page_range[t]-page_range[t-1] if step>=2: if step==2: page_range.insert(t,page_range[t]-1) else: page_goto = page_range[t-1] + 1 page_range.insert(t,'...') t+=1 t+=1 #优化结果之后的页码列表 paginator.page_range_ex = page_range #默认跳转页的值 paginator.page_goto = page_goto return paginator,objectlist
加上比较的页码之后,可能出现超出范围和重复,再修正一次即可。
例如当前页是4,会得到[1, 3, 4, 5, 8]这个列表。接着进一步判断相邻元素相差多少。
相差1就是连续的,无需处理;
相差2就是前面提到的把省略号去掉,显示原本的页码;
相差3极其以上的,就加上省略号即可。
最终得到列表[1, 2, 3, 4, 5, '...', 8],再把这个列表传递给html模版即可。
在传递这个列表时候,不想再额外返回多一个对象。而paginator.page_range是只读的,不能赋值。
于是,赋值到paginator.page_range_ex中,该属性是自定义的,原本不存在。这个是利用python的特性,可以在对象额外加属性。这个属性可以在其他地方获取得到对应的值。
同样,那个跳转页码的默认值也是采用这种方式保存到分页器中。
按照我第3天写的分页器代码。响应博文列表的处理方法是不需改动的。这里也写出来(只写关键部分的代码),以便分析html模版代码:
#coding:utf-8 from django.shortcuts import render_to_response from blog.models import Blog from helper.paginator import getPages #封装的分页器方法 def index(request): """show blogs' list""" blogs = Blog.objects.all() pages,blogs=getPages(request,blogs) data = {} data["blogs"]=blogs data["pages"]=pages return render_to_response('blog/blog_list.html',data)
最后,修改一下html模版(html代码比较多,我只写关键部分):
<div class="blog_list_footer"> <span class="blog_footer_tip"> 共{{pages.count}}篇博文。 当前第{{blogs.number}}页, 共{{pages.num_pages}}页 </span> <div> <ul class="pagination"> <li> <a href="?page= {% if blogs.has_previous %} {{blogs.previous_page_number}} {% else %} {{blogs.number}} {% endif %} " aria-label="Previous"> <span aria-hidden="true">«</span> </a> </li> {% for page in pages.page_range_ex %} {% if page == '...' %} <li><span>...</span></li> {% else %} <li><a href="?page={{page}}">{{page}}</a></li> {% endif %} {% endfor %} <li> <a href="?page= {% if blogs.has_next %} {{blogs.next_page_number}} {% else %} {{blogs.number}} {% endif %} " aria-label="Next"> <span aria-hidden="true">»</span> </a> </li> </ul> {# 页码跳转的html代码 #} <ul class="pagination"> <li id="page_goto"> <span > <input type="text" value="{{paginator.page_goto}}" /> </span> </li> <li><a href="javascript:void(0);" onClick="page_goto();">Go</a></li> </ul> </div> </div>
这里的html模版和之前的基本一样,具体分析可以看之前的博文:我的网站搭建(第3天) Django分页器。不同的地方是在遍历的部分加了if判断。判断内容是不是省略号,若是省略号就用span标签。而且加上跳转页码的html代码。
这里还需要改动js代码:
<script type="text/javascript"> {#设置凸显当前页码#} $(".pagination li a").each(function(){ if($(this).text()=="{{blogs.number}}"){ $(this).parent().addClass("active"); } }); {#页码跳转处理#} function page_goto(){ var page = $("#page_goto input")[0].value; window.location.href = '?page=' + page; //重定向 return false; } </script> <style type="text/css"> {#页码跳转的显示样式#} #page_goto span{ padding: 6px 4px; } #page_goto input{ border: none; padding: 0; width: 2em; text-align: center; } </style>
最终效果如下: