分页算法

分页

分页算是我们最日常能接触的东西了, 写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;
    }
}

发表评论

电子邮件地址不会被公开。 必填项已用*标注