tp程序自帶了分頁的功能逆趋,用起來很是方便哮伟,特別是默認(rèn)情況下直接連樣式都寫好了正蛙。非常的省心统阿。但這只是對于數(shù)據(jù)庫操作而言逗柴。如果我們想要對請求的接口數(shù)據(jù)進(jìn)行分頁灾锯,那么該如何使用paginate方法呢爆哑?
修改說明
增加了注釋呻待,參考附錄代碼砰盐。
此代碼的使用場景:在php中curl請求帶分頁的接口中使用
解決html顯示異常肿仑,模板中使用raw方法
知其然
我們首先來查看tp數(shù)據(jù)的分頁流程是怎么樣的谈撒。先寫一個(gè)數(shù)據(jù)庫分頁的代碼
$page = Db::name("null")
->paginate();
$page->render();
使用ctrl+鼠標(biāo)左鍵腥泥,進(jìn)入paginate方法中。
...
/** @var Paginator $class */
$class = false !== strpos($config['type'], '\\') ? $config['type'] : '\\think\\paginator\\driver\\' . ucwords($config['type']);
$page = isset($config['page']) ? (int) $config['page'] : call_user_func([
$class,
'getCurrentPage',
], $config['var_page']);
$page = $page < 1 ? 1 : $page;
$config['path'] = isset($config['path']) ? $config['path'] : call_user_func([$class, 'getCurrentPath']);
if (!isset($total) && !$simple) {
$options = $this->getOptions();
unset($this->options['order'], $this->options['limit'], $this->options['page'], $this->options['field']);
$bind = $this->bind;
$total = $this->count();
$results = $this->options($options)->bind($bind)->page($page, $listRows)->select();
} elseif ($simple) {
$results = $this->limit(($page - 1) * $listRows, $listRows + 1)->select();
$total = null;
} else {
$results = $this->page($page, $listRows)->select();
}
return $class::make($results, $listRows, $page, $total, $simple, $config);
這里只粘貼了重要代碼啃匿。我們看最后一句蛔外,$class 的實(shí)例化在上面代碼塊的第一行,這個(gè)類就是分頁驅(qū)動類溯乒。調(diào)用了make方法夹厌。我們再跟蹤進(jìn)make方法進(jìn)行查看
public static function make($items, $listRows, $currentPage = null, $total = null, $simple = false, $options = [])
{
return new static($items, $listRows, $currentPage, $total, $simple, $options);
}
我們可以看一下參數(shù)名,currentPage裆悄,當(dāng)前頁矛纹,totoal總共。這里應(yīng)該就是我們要找的分頁方法了灯帮。
/** @var bool 是否為簡潔模式 */
protected $simple = false;
/** @var Collection 數(shù)據(jù)集 */
protected $items;
/** @var integer 當(dāng)前頁 */
protected $currentPage;
/** @var integer 最后一頁 */
protected $lastPage;
/** @var integer|null 數(shù)據(jù)總數(shù) */
protected $total;
/** @var integer 每頁的數(shù)量 */
protected $listRows;
/** @var bool 是否有下一頁 */
protected $hasMore;
/** @var array 一些配置 */
protected $options = [
'var_page' => 'page',
'path' => '/',
'query' => [],
'fragment' => '',
];
擼起袖子干
我們接下來可以試著寫個(gè)demo調(diào)用一下看看崖技。
make 方法需要傳入的參數(shù)都已經(jīng)在paginate類里聲明過了。都是漢語注釋钟哥。
$result = $this->api();
$total = count($result);
$page = Paginator::make(null, 10, 0, $total, false, []);
$this->assign("data", $result);
$this->assign("page", $page);
我們這里值先嘗試進(jìn)行傳遞迎献,出錯之后再進(jìn)行修改。訪問這個(gè)方法腻贰。發(fā)現(xiàn)系統(tǒng)報(bào)錯了
Cannot instantiate abstract class think\Paginator
paginator 是一個(gè)抽象類吁恍,無法實(shí)例化,那這個(gè)時(shí)候我們需要找到他的實(shí)現(xiàn)類是哪一個(gè)播演。得益于intellij方便的index功能冀瓦,我們只需要ctrl+鼠標(biāo)左鍵點(diǎn)擊Pageinator這個(gè)類的名字,我們會發(fā)現(xiàn)長長的列表中有一個(gè)驚喜
class Bootstrap extends Paginator
我們實(shí)例化Bootstrap試一下写烤。代碼如下
public function page()
{
//模擬接口請求
$result = $this->api();
$total = count($result);
$page = Bootstrap::make(null, 10, 0, $total, false, []);
$this->assign("data", $result);
$this->assign("page", $page);
return $this->fetch();
}
private function api()
{
return ["最后的生還者", "神秘海域", "塞爾達(dá)傳說", "獵天使魔女", "光環(huán)", "極品飛車", "使命召喚", "最后的守護(hù)者", "戰(zhàn)神", "鬼泣", "仁王",
"超級馬里奧", "地平線-零之曙光", "怪物獵人", "DOOM", "無冬", "風(fēng)之旅人"];
}
這時(shí)候我們發(fā)現(xiàn)翼闽,我們的分頁已經(jīng)顯示出來了,只不過效果很難看洲炊。tp分頁渲染使用的是bootstrap感局,從上面類的名字我們也能夠看的出來尼啡。我們引入bootstrap試試
引入css樣式之后,我們發(fā)現(xiàn)分頁效果已經(jīng)炫酷了很多了询微。
查詢參數(shù)及url路徑
如果是在搜索中用到分頁崖瞭,那么分頁之后的url帶有搜索關(guān)鍵字就更好了,不然點(diǎn)機(jī)第二頁撑毛,不知到搜索的是什么了就很尷尬书聚。我們看一下make的最后一個(gè)參數(shù) option,選項(xiàng)
/** @var array 一些配置 */
protected $options = [
'var_page' => 'page',
'path' => '/',
'query' => [],
'fragment' => '',
];
這里是一個(gè)數(shù)組藻雌,里面有一個(gè)query字段雌续,也是一個(gè)數(shù)組,那么我們嘗試著使用一下這個(gè)字段看看效果如何蹦疑。修改make方法的參數(shù)
options 參數(shù)中有一個(gè)字段時(shí)path西雀,上面可以看到默認(rèn)值為 / 也就是根目錄,如果我們傳入了這個(gè)值歉摧,就可以設(shè)置分頁后的url了
$page = Bootstrap::make(null,
10,
0,
$total,
false,
["query" => ["key" => "game"], 'path' => '/index/index/page']);
我們傳入了query和path這個(gè)字段,看看效果吧
這個(gè)時(shí)候url里不僅包含了頁碼腔呜,還包含了關(guān)鍵字和路徑叁温,PHP端就能方便的知道下一個(gè)頁面該展示什么了。
make第一個(gè)參數(shù)核畴,數(shù)據(jù)集也是很有用的東西膝但,可以實(shí)現(xiàn)數(shù)據(jù)和分頁通過一個(gè)paginator傳遞到前端頁面,類似于數(shù)據(jù)庫請求那樣谤草。我們講上面的代碼簡單改動跟束,就可以實(shí)現(xiàn)
public function page()
{
//模擬接口請求
$result = $this->api();
$total = count($result);
$page = Bootstrap::make($result,
10,
0,
$total,
false,
["query"=>["key"=>"game"]]);
//$this->assign("data", $result);
$this->assign("page", $page);
return $this->fetch();
}
這樣的話我們還可以少進(jìn)行一次assign操作。
下面是上面演示用到的代碼
附上后端代碼
<?php
namespace app\index\controller;
use think\Controller;
use think\paginator\driver\Bootstrap;
class Index extends Controller
{
/**
* 這套代碼不對數(shù)據(jù)進(jìn)行分頁處理丑孩,只是一個(gè)將已經(jīng)分頁后的數(shù)據(jù)冀宴,套用tp的分頁方法,可以少一個(gè)自己寫分頁
* 使用是有場景限制的温学,建議是在php請求帶分頁的接口略贮,然后返回?cái)?shù)據(jù)給html時(shí)候使用
* 直接請求數(shù)據(jù)庫時(shí)tp自帶分頁
* 前端直接請求接口時(shí)前端可以自行分頁
* @return mixed
*/
public function page()
{
$page = input('page');
//模擬接口請求
//從接口種獲取$page頁的數(shù)據(jù)
$result = $this->api($page);
//從接口中獲取總數(shù)據(jù),這里應(yīng)該是個(gè)固定值仗岖,因?yàn)椴樵儣l件不變的話逃延,總數(shù)據(jù)一搬不會變。
//方便演示直接寫死了轧拄,正常應(yīng)該是從接口中獲取
$total = 18;
//進(jìn)行分頁揽祥,這里第二個(gè)參數(shù)是每頁數(shù)據(jù),應(yīng)該和接口中的每頁數(shù)據(jù)相同
//最后一個(gè)參數(shù)中的path檩电,如果不指定就會從根目錄開始
$page = Bootstrap::make($result,
10,
$page,
$total,
false,
["query" => ["key" => "game"], 'path' => '/index/index/page']);
//上面第一個(gè)參數(shù)已經(jīng)帶了數(shù)據(jù)拄丰,所以這個(gè)assign可以取消
//$this->assign("data", $result);
$this->assign("page", $page);
return $this->fetch();
}
/**
* @param $page int 頁碼
* @return mixed
* 這里是數(shù)據(jù)模擬府树,正常情況下這里可能是curl訪問數(shù)據(jù)接口。
* 數(shù)據(jù)分頁獲取在數(shù)據(jù)接口請求數(shù)據(jù)庫時(shí)候操作
*/
private function api($page)
{
$data = [
"1" => ["最后的生還者", "神秘海域", "塞爾達(dá)傳說", "獵天使魔女", "光環(huán)", "極品飛車", "使命召喚", "最后的守護(hù)者", "戰(zhàn)神", "鬼泣", "仁王"],
"2" => ["超級馬里奧", "地平線-零之曙光", "怪物獵人", "DOOM", "無冬", "風(fēng)之旅人"]
];
return $data[$page];
}
}
附上前端頁面代碼
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"><!-- 最新版本的 Bootstrap 核心 CSS 文件 -->
<link rel="stylesheet"
integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<!-- 可選的 Bootstrap 主題文件(一般不用引入) -->
<link rel="stylesheet"
integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp" crossorigin="anonymous">
<!-- 最新的 Bootstrap 核心 JavaScript 文件 -->
<script src="https://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"
integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa"
crossorigin="anonymous"></script>
<title>分頁測試</title>
</head>
<body style="border: 25px">
<table class="table-striped table">
{volist name="page" id="item"}
<tr>
<td>{$item}</td>
</tr>
{/volist}
</table>
<!---如果顯示的是html代碼愈案,加上raw方法后會正常顯示-->
{$page->render()|raw}
</body>
</html>
附上我自己項(xiàng)目中用到的一個(gè)分頁服務(wù)代碼
<?php
namespace app\common\service;
use think\paginator\driver\Bootstrap;
class PageService
{
/**
* 只負(fù)責(zé)生成分頁信息挺尾,不攜帶數(shù)據(jù)
* @param $total 總數(shù)據(jù)量
* @param $pageSize 每頁大小
* @param $page 當(dāng)前頁
* @param $path 路徑
* @param array $query ["query"=>["key"=>"game"]]
* @return mixed
*/
public function onlyPage($total, $pageSize, $page, $path, $query = [])
{
$page = Bootstrap::make([],
$pageSize,
$page,
$total,
false,
["query" => $query,"path"=>$path]);
return $page;
}
}
使用分頁工具
//$galley 是接口請求得到的數(shù)據(jù),20是接口中數(shù)據(jù)庫分頁大小站绪,$page是當(dāng)前頁碼
//剩下兩個(gè)參數(shù)分別為路徑和查詢參數(shù)
$pages = (new PageService())->onlyPage($galley['count'],20, $page,
'/intro/galley/zwgx.html',['galley_cate_id'=>$galley_cate_id]);
$this->assign("pages", $pages);