需求(Demand )
因为博客以前用的wordpress的缘故,所以基本上的路由沿用了wordpress的规则。 在wordpress中文章按日期归档比较灵活:
article/date/年
article/date/年/月
article/date/年/月/日
article/date/年/page/页码
article/date/年/月/page/页码
article/date/年/月/日/page/页码
好在thinkjs在路由这块也很灵活,研究了几天,总算给实现了😴
关键点(Key Point)
分页api
thinkjs中专门提供了pageapi来进行分页查询数据
model.page(page, listRows)
- page {Number} 当前页,从 1 开始
- listRows {Number} 每页的条数
- return {this}
自定义路由之正则路由(router)
路由配置src/home/config/route.js
export default [
[/^article\/date\/(\d+)$/, "home/article/date?year=:1"]
];
上面的正则会匹配类似 article/date/2016 这样的 pathname,识别后新的 pathname 为 home/article/date,也就是对应到了home模块下的article控制器的dateAction,并且将捕获到的值赋值给参数 year ,这样在控制器里就可以通过 this.get 方法 来获取该值。
这里很关键,捕获的值来源于正则里的子分组(\d+),如果有多个则可以通过在路由配置中用 :1,:2,:3 来获取对应的值。
分页查询数据(countSelect)
这个方法与page方法配合,thinkjs会帮我们返回总页数,当前页码,每页显示页数等信息,这些都是后面分页模板编写的基础。
返回值格式如下:
{
numsPerPage: 10, //每页显示的条数
currentPage: 1, //当前页
count: 100, //总条数
totalPages: 10, //总页数
data: [{ //当前页下的数据列表
title: "文章标题",
author: "文章作者",
desc:"文章摘要"
}, ...]
}
模板(template)
有了数据,在页面要显示出来自然少不了模板 之前选择的是nunjucks模板引擎(很强大的js模板引擎模仿的python的jinja2引擎),所以实现起来也相对轻松,我准备把它提取成公用的模板,命名为pagination.由于每个分页的模块对应路由肯定各不相同,所以还得做点额外工作,这里我把前缀提取了出来,用一个变量来标识.
实践(Practice)
template
<div class="pagination">
{% if pageData.prevPage%}
<a class="btn-prev" href="{{pageFor}}page/{{pageData.prevPage}}">上一页</a>
{% endif %}
{% for i in range(pageData.pageStart, pageData.pageEnd+1) -%}
<a href="{{pageFor}}page/{{i}}" class="pagination-item {%if pageData.currentPage==i %}active{%endif%}">{{i}}</a>
{%- endfor %}
{% if pageData.nextPage%}
<a class="btn-next" href="{{pageFor}}page/{{pageData.nextPage}}">下一页</a>
{% endif %}
<span class="count">共 {{pageData.pageCount}} 页</span>
</div>
controller
async dateAction() {
let params = this.get();
let startDate, endDate,date,query,title,pageFor;
let currentPage = this.get("page")||1;
let pagesize = this.get("pagesize")||10;
// 如果具体到天
if(params.day) {
date = new Date(params.year,params.month - 1,params.day);
startDate = date.getTime();
endDate = startDate + 3600*24*1000;
title = "归档:\""+ think.datetime(date,"YYYY年MM月DD日") + "\"";
pageFor = "/article/date/" + params.year + '/' + (params.month+1) + '/'+ params.day + '/';
}
query = {"create_time":{$gte:new Date(startDate),$lte:new Date(endDate)},"status": 1};
let model = this.model("article");
let list = await model.where(query).page(currentPage,pagesize).countSelect();
let pageData = this.pagination(list);
if(list && list.data.length>0){
this.assign({
"list":list,
"title":title,
pageData:pageData,
pageFor:pageFor
});
return this.displayView('list');
} else {
this.errorHandler.displayError(404);
}
}
/**
* @description 处理分页数据
*/
pagination($list){
let pageNum = 6; //最大显示的分页按钮数
let pageStart = 1;
let pageEnd = 6;
let pageCount = $list.totalPages;
let currentPage = $list.currentPage;
let nextPage = currentPage + 1 <= pageCount ? currentPage + 1:null;
let prevPage = currentPage - 1 || null;
if(currentPage<=pageNum/2+1){
pageStart=1;
pageEnd=pageNum;
}else{
pageStart=currentPage - pageNum / 2;
pageEnd = currentPage + pageNum / 2 - 1;
}
if (pageEnd >pageCount) {
pageEnd = pageCount;
}
if (pageEnd <= pageNum) {
pageStart= 1;
}
return {
pageCount:pageCount,
nextPage:nextPage,
prevPage:prevPage,
currentPage:currentPage,
pageStart:pageStart,
pageEnd:pageEnd
}
}
总结(Summary)
起初用的自定义之规则路由:
export default [
["group/:year/:month", "home/group/list"]
]
谁知道遇到了蛮多坑的,不分页时还好,年月日三种路由都能正常匹配。不过加上分页后,就悲剧了😫
export default [
["article/date/:year/:month/:day", "home/article/date"],
[/^article\/date\/(\d+)\/page\/(\d+)$/, "home/article/date?year=:1&page=:2&pagesize=10"]
]
上述两个路由就开始互掐了,后面索性全用了正则路由,再次觉得正则真心强大。希望以上写的略显琐碎笔记对需要在thinkjs进行分页的同学有所帮助😁(End).