TP 5 分页很方便,但 TP 3.2 分页就很麻烦。虽然现在新项目都是用 TP 5,但很多老项目还是用 TP 3.2,为维护方便,还是动手去优化了 TP 3.2 的分页实现。
TP 3.2 分页,有几个方面要处理:
1)取得当前页号、每页数据条数;
2)取得指定页面数据;
3)渲染分页导航 html 代码。
2019-04-15 bug 修复:修复可能出现页数错误的 bug。
直接先看代码:
一、添加分页类:
<?php
/**
* User: Aven
* Date: 2019-04-03
* Time: 14:14
*/
namespace Lib;
use Think\Page;
class Paginator implements \ArrayAccess,\Countable,\IteratorAggregate
{
protected $_items = [];
protected $rowsList;
protected $options;
protected $totalRows;
protected $prev;
protected $next;
function __construct($items, $totalRows, $rowsList = 15, $options = [])
{
$this->_items = $items;
$this->rowsList = $rowsList;
$this->options = $options;
$this->totalRows = $totalRows;
}
public function render()
{
$page = new Page($this->totalRows, $this->rowsList);
if ($this->prev){
$page->setConfig('prev', $this->prev);
}
if ($this->next){
$page->setConfig('next', $this->next);
}
return $page->show();
}
public function items()
{
return $this->_items;
}
public function each(callable $callback)
{
foreach ($this->_items as $key => $item) {
$result = $callback($item, $key);
if (false === $result) {
break;
} elseif (!is_object($item)) {
$this->_items[$key] = $result;
}
}
return $this;
}
public function setPrev($prev){
$this->prev = $prev;
return $this;
}
public function setNext($next) {
$this->next = $next;
return $this;
}
public function slice($offset, $length = null, $preserveKeys = false)
{
return array_slice($this->_items, $offset, $length, $preserveKeys);
}
public function count()
{
return count($this->_items);
}
public function offsetExists($offset)
{
return isset($this->_items[$offset]);
}
public function offsetGet($offset)
{
return $this->offsetExists($offset) ? $this->_items[$offset] : null;
}
public function offsetSet($offset, $value)
{
$this->_items[$offset] = $value;
}
public function offsetUnset($offset)
{
unset($this->_items[$offset]);
}
public function getIterator()
{
return new \ArrayIterator($this->_items);
}
}
二、修改 Model 类,为 model 添加功能。// $rowsList 为每页数据条数
// $data_only 为 true 时,只返回数据,不作渲染、不统计数据总条数,提高性能,主要为接口提供数据用。
// 2019-04-15 bug 修复
public function paginate($rowsList = 15, $data_only = false)
{
$currentPage = I(C('VAR_PAGE') ? C('VAR_PAGE') : 'p', 1);
// 添加一行,备份 options,因为每进行一次查询,都会清了 options。
$options = $this->options;
$items = $this->page($currentPage, $rowsList)->select();
if ($data_only){
return $items;
}
// 添加一行,恢复 options。
$this->options = $options;
$totalRows = $this->count();
return new \Lib\Paginator($items, $totalRows, $rowsList);
}
三、修改模板渲染文件,让 volist 标签识别分页类数据。修改以下的代码即可。 $parseStr .= 'if(is_array('.$name.') || ' . $name . ' instanceof \Lib\Paginator): $'.$key.' = 0;';
if(isset($tag['length']) && '' != $tag['length'] ) {
$parseStr .= ' $__LIST__ = ' . $name . ' instanceof \Lib\Paginator ? ' . $name . '->array_slice(' . $name.','.$tag['offset'].','.$tag['length'] . ',true) : array_slice('.$name.','.$tag['offset'].','.$tag['length'].',true);';
}elseif(isset($tag['offset']) && '' !=$tag['offset']){
$parseStr .= ' $__LIST__ = ' . $name . ' instanceof \Lib\Paginator ? ' . $name . '->array_slice(' . $name.','.$tag['offset'].','.$tag['length'] . ',true) : array_slice('.$name.','.$tag['offset'].',null,true);';
}else{
$parseStr .= ' $__LIST__ = ' . $name . ';';
}
四、现在使用就简单了:$data = M('User')->where(array('rank' => 2))->order('id asc')->paginate(20);
//只要数据就这样
$data = M('User')->paginate(20, true);
其它说明:1)页号参数,按 TP 3.2 的分页类,默认为 p,可以在配置文件中配置 VAR_PAGE 即可。
2)分页也像 TP 5 的分页一样,带 each 方法。
3)本次优化,是实现主要的、常用的功能,要实现其它功能,看官自行完善。