分页
分页算是我们最日常能接触的东西了, 写SQL分页获取, 列表的分页获取等等. 今天偶尔写服务端渲染的时候, 发现需要渲染分页, 细细写来发现需要注意的东西还是很多.
需求
第一个和最后一个是首尾页
第一页的时候, 最前面一个选中状态, 最后一个的时候是最后一个选中状态
中间的时候中间选中状态, 两边的选择数量应该是相等的, 如果全面不足或后面不足, 那么另一边应该补上, 如上图
条件
我们能从客户端获得的offset, limit, 能从服务器获取到所有的个数count.
###算法
搜索算法, 从当前页开始搜索, 每次搜索前后两个, 条件成立则加入, 不成立则搜索下一个. 直到获取到需要的个数, 或是所有条件都不满足.
编码(PHP)
$offset = InputGet::val('offset', 0); // 获取到offset
$limit = InputGet::val('limit', 5); // 获取到count
$pages = ArticleSearchHandler::instance()->getPageInfo();
// 需要计算的长度
$count = 4;
// 第一个就是当前页码
$data = [];
$data[0] = [];
$data[0]['limit'] = $limit;
$data[0]['offset'] = $offset;
// 剩下有四个,需要搜索四个
for($i = 1; $i < 5; $i++)
{
$before = [];
$before['offset'] = $offset - $i * $limit;
$before['limit'] = $limit;
if ($before['offset'] + $limit > 0) {
if ($before['offset'] < 0) { // 特殊处理第一页
$before['offset'] = 0;
}
$data[] = $before;
$count--;
}
if ($count <= 0)
break;
$after = [];
$after['offset'] = $offset + $i * $limit;
$after['limit'] = $limit;
if ($after['offset'] < $pages['count']) {
$data[] = $after;
$count--;
}
if ($count <= 0)
break;
}
// 首尾加一个
$first = [];
$first['offset'] = 0;
$first['limit'] = $limit;
$data[] = $first;
$last = [];
$last['offset'] = $pages['count'] - $limit > 0 ? $pages['count'] - $limit : 0;
$last['limit'] = $limit;
$data[] = $last;
// 通过offset 排序, 获得整个序列
usort($data, function($a, $b) {
return $a['offset'] > $b['offset'];
});
// 处理当前是否选中
foreach ($data as $key => $value)
{
// 计算当前页面,
if ($key == 0)
$data[$key]['index'] = '<';
else if ($key == count($data) - 1) {
$data[$key]['index'] = '>';
} else {
$data[$key]['index'] = ceil($data[$key]['offset'] / $data[$key]['limit'] + 1);
}
$data[$key]['url'] = '/' . Yii::$app->request->getPathInfo() . "?offset=" . $data[$key]['offset'] . '&limit=' . $data[$key]['limit'];
if ($data[$key]['offset'] == $offset) {
$data[$key]['active'] = true;
} else {
$data[$key]['active'] = false;
}
}
欢迎大家订阅雀观代码, 我将给你讲述, 中小企业程序员, 淘金路上的故事.