关于本站
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>
最终效果如下: