我們在項目開發的過程中避免不了使用分頁功能,拿php來說,現在市面上有很多大大小小的php框架,當然了分頁這種小功能這些框架中都是拿來直接可以用的。
這些框架的分頁功能使用都很方便,配置一下分頁所需參數立馬就能出結果,對於開發人員來說是非常方便的。但是有些時候就會發現這些分頁功能不是自己期望的,
當然拿框架的分頁修改一下是可以實現我們的需求的,但是永遠局限於框架本身的封裝,那么我們怎么樣定義自己的分頁類呢,那么現在就要求我們不僅要知其然,更要知其所以然,
好了,廢話那么多,咱們開始正題。
要實現分頁功能,首先要知道數據總條數、每頁顯示的條數、顯示幾個分頁碼,這三個可謂是必要條件。
我們先看一下具體的實現效果
假設表結構是這樣
CREATE TABLE `article_information` ( `inf_id` int(10) unsigned NOT NULL AUTO_INCREMENT, `inf_title` varchar(50) NOT NULL DEFAULT '', `inf_smtitle` varchar(50) NOT NULL DEFAULT '', `inf_cid` int(10) unsigned NOT NULL, `inf_hits` int(10) unsigned NOT NULL DEFAULT '0', PRIMARY KEY (`inf_id`) ) ENGINE=MyISAM AUTO_INCREMENT=210 DEFAULT CHARSET=utf8;
首先我們連接數據庫,php代碼為:
$host = '127.0.0.1'; $db_user = 'root'; $db_pass = 'root'; $db_name = 'article'; $link = new mysqli($host,$db_user,$db_pass); if($link->errno){ printf("數據庫鏈接失敗:".mysqli_connect_error()); exit(); } if( ! $link->select_db($db_name)){ printf("數據庫選擇失敗"); exit(); } $count_sql = "SELECT COUNT(1) nums FROM article_information";//查詢數據總條數 $query = $link->query($count_sql); $row_count = $query->fetch_assoc(); $query->free_result(); $total = $row_count['nums']; $page_size = 10; $cur_page = get_url_param(parse_url($_SERVER['REQUEST_URI'])['path'],4); //假如url鏈接為,http://xxx.net/fenye.php/index/list/6?age=20&city=40 //我這邊以平常開發常用的url鏈接為例,我這個鏈接只有兩層index/list,如果是tp的話無路由鏈接一般為index/index/list(模塊/控制器/方法)
get_url_param函數為:
/** * 獲取url中的分段數據 * @param $url 鏈接url * @param $seg 獲取url中的第幾段 */ function get_url_param($url,$seg){ $url = explode('/',$url); return isset($url[$seg]) ? $url[$seg] : 1; }
接着繼續,知道了總條數和每頁顯示的條數以后,下面我們開始取頁碼范圍內的數據
$start = ($cur_page-1)*$page_size;//按照分頁規律計算出數據起始條數 $sql = "SELECT inf_id,inf_title FROM py_information LIMIT $start,$page_size"; if ($result = $link->query($sql)){ $arr = []; while ($row = $result->fetch_assoc()){ $arr[] = $row; } }
現在我們已經把數據取出來了,下面我們開始寫分頁類。
下面是分頁類的初始化配置:
具體配置參數我已經注釋的很詳細了,個別說明一下
$params參數:很多時候我們列表的分頁會用到很多的查詢參數,我經常看到各個框架論壇里面有同學問怎么把搜索參數帶入到分頁里面,那么這個參數就是讓你把你的篩選參數組合到url中,格式為?id=20&city=30,
下面我們會講如何將參數組合成這種格式的。
$base_url參數:當前鏈接(不帶參數和頁碼),例如我們當前訪問的地址為:http://xxx.net/fenye.php/index/list/6?age=20&city=40,那么$base_url =/fenye.php/index/list,我這是用原生php寫的例子,如果用框架的話相關php文件是可以省略的。
class Mypage{ private $cur_page;//當前頁 private $total;//總條數 private $page_size = 10;//每頁顯示的條數 private $total_page;//總頁數 private $first_page;//首頁顯示名稱 private $pre_page;//上一頁的顯示名稱 private $nex_page;//下一頁的顯示名稱 private $end_page;//尾頁名稱 private $params;//分頁后面的篩選參數 private $num_size = 2;//當前頁前后顯示幾個分頁碼 private $base_url;//分頁鏈接地址 public function __construct(array $page_config=[]) { $this->cur_page = $page_config['cur_page']; $this->total = $page_config['total']; $this->page_size = $page_config['page_size']; $this->base_url = $page_config['base_url']; $this->pre_page = isset($page_config['pre_page']) ? $page_config['pre_page'] : "上一頁"; $this->nex_page = isset($page_config['next_page']) ? $page_config['next_page'] : "下一頁"; $this->end_page = isset($page_config['end_page']) ? $page_config['end_page'] : "尾頁"; $this->first_page = isset($page_config['first_page']) ? $page_config['first_page'] : "首頁"; $this->num_size = isset($page_config['num_size']) ? $page_config['num_size'] : 2; $this->params = isset($page_config['params']) ?$page_config['params'] : ''; $this->total_page = ceil($this->total/$this->page_size); }
}
配置好分頁類,那么下一步我們就要獲取分頁碼了,像下面圖片中的分頁樣式一樣。
我們來看一下一個分頁地址需要哪些東西,假如第5頁的鏈接地址為:
<a href="/fenye.php/index/list/5?age=20&city=40">5</a>
首先我們要組合第5頁的鏈接地址/fenye.php/index/list/5?age=20&city=40,然后再返回<a href="/fenye.php/index/list/5?age=20&city=40">5</a>這個鏈接,
下面我們來具體實現
獲取指定頁碼的地址:
/** * 獲取分頁地址 xxx.com/index/3 * @param $i */ public function get_url($i){ return $this->base_url.'/'.$i; }
返回整體頁碼鏈接,上面我們已經說了分頁參數問題,這里$url.=$this->params就是對每一頁的url后面都帶上分頁參數,這樣就確保參數的正確性:
/** * 獲取分頁完整鏈接 * @param $url */ public function get_link($url,$text){ if ($this->params) $url.=$this->params; return "<a href='$url'>$text</a>"; }
有了上面兩個函數,現在我們來獲取一下第1頁的頁碼鏈接,下面做了一個小小的判斷,我想大家都能看明白,就是當前不是第一頁就返回有鏈接的地址,否則只返回一個鏈接名稱:
/** * 獲取首頁的鏈接地址 */ public function get_first_page(){ if ($this->cur_page > 1 && $this->cur_page != 1){ return $this->get_link($this->get_url(1),$this->first_page); } return "<span>$this->first_page</span>"; }
和上面類似,我們獲取一個其它頁碼的鏈接地址:
/** * 獲取上一頁鏈接地址 */ public function get_prev_page(){ if ($this->cur_page > 1 && $this->cur_page !=1){ return $this->get_link($this->get_url($this->cur_page-1),$this->pre_page); } return '<span>'.$this->pre_page.'</span>'; } /** * 獲取下一頁鏈接地址 * @return string */ public function get_next_page(){ if ($this->cur_page < $this->total_page){ return $this->get_link($this->get_url($this->cur_page+1),$this->nex_page); } return '<span>'.$this->nex_page.'</span>'; } /** * 獲取...符號 * @return string */ public function get_ext(){ return '<span>...</span>'; } /** * 獲取尾頁地址 */ public function get_end_page(){ if ($this->cur_page < $this->total_page){ return $this->get_link($this->get_url($this->total_page),$this->end_page); } return '<span>'.$this->end_page.'</span>'; }
還差一點,就是中間的數字頁碼,注釋我已經寫得很清楚了:
/** * 中間的數字分頁 */ public function now_bar(){ if ($this->cur_page > $this->num_size){ $begin = $this->cur_page - $this->num_size; $end = $this->cur_page + $this->num_size; //判斷最后一頁是否大於總頁數 if ($end > $this->total_page){ //重新計算開始頁和結束頁 $begin = ($this->total_page - 2*$this->num_size > 0) ? $this->total_page - 2*$this->num_size : 1; //這里為什么用2*$this->num_size呢?因為當前頁前后有2個$this->num_size的間距,所以這里是2*$this->num_size $end = $this->total_page; } }else{ $begin = 1; $end = 2*$this->num_size+1;//此處的2和上面已經解釋過了,+1是因為除了當前頁,前后還有2*$this->num_size的間距,所以總頁碼條數為2*$this->num_size+1 } $page_html=''; for ($i=$begin;$i<=$end;$i++){ if ($i == $this->cur_page){ $page_html .= '<span class="disabled">'.$i.'</span>'; }else{ $page_html .= $this->get_link($this->get_url($i),$i); } } return $page_html; }
其它的兩個函數
/** * 返回總條數 * @return string */ public function show_total_row(){ return "共{$this->total}條"; } /** * 返回總頁數 */ public function show_total_page(){ return "共{$this->total_page}頁"; }
最后輸出分頁:
/** * 輸出分頁碼 */ public function show_page(){ $show_page = ''; $ext = ($this->cur_page>$this->num_size) ? $this->get_ext() : ''; $show_page.= $this->show_total_row(); $show_page.= $this->show_total_page(); $show_page.= $this->get_first_page(); $show_page.= $this->get_prev_page(); $show_page.= $ext; $show_page.= $this->now_bar(); $show_page.= $ext; $show_page.= $this->get_next_page(); $show_page.= $this->get_end_page(); return $show_page; }
以上就是分頁的實現原理,下面我會給出具體代碼,上面我們說過我們的查詢參數組裝成?id=20&city=30這種格式的來拼接到url后面,下面我們來看一下具體實現過程。
例如我們把分頁條件都放進一個數組中:
$condition = [ 'age'=>20, 'city'=>40 ];
下面我們來進行url組合:
/** * 組合url參數 ?id=2&city=3 * @param array $data */ function make_url(array $data=[]){ $link = '?'; $suffix = '&'; foreach ($data as $key=>$val){ $link .= $key.'='.$val.$suffix; } return trim($link,$suffix); }
ok參數已經組合成我們所希望的格式了,其實就是一個foreach拼裝數據的過程。
以上是一個原理和邏輯,下面給出所有代碼:
完整分頁類:
<?php /** * Created by PhpStorm. * User: 123456 * Date: 2018/9/4 * Time: 17:24 */ class Mypage{ private $cur_page;//當前頁 private $total;//總條數 private $page_size = 10;//每頁顯示的條數 private $total_page;//總頁數 private $first_page;//首頁顯示名稱 private $pre_page;//上一頁的顯示名稱 private $nex_page;//下一頁的顯示名稱 private $end_page;//尾頁名稱 private $params;//分頁后面的篩選參數 private $num_size = 2;//當前頁前后顯示幾個分頁碼 private $base_url;//分頁鏈接地址 public function __construct(array $page_config=[]) { $this->cur_page = $page_config['cur_page']; $this->total = $page_config['total']; $this->page_size = $page_config['page_size']; $this->base_url = $page_config['base_url']; $this->pre_page = isset($page_config['pre_page']) ? $page_config['pre_page'] : "上一頁"; $this->nex_page = isset($page_config['next_page']) ? $page_config['next_page'] : "下一頁"; $this->end_page = isset($page_config['end_page']) ? $page_config['end_page'] : "尾頁"; $this->first_page = isset($page_config['first_page']) ? $page_config['first_page'] : "首頁"; $this->num_size = isset($page_config['num_size']) ? $page_config['num_size'] : 2; $this->params = isset($page_config['params']) ?$page_config['params'] : ''; $this->total_page = ceil($this->total/$this->page_size); } /** * 獲取首頁的鏈接地址 */ public function get_first_page(){ if ($this->cur_page > 1 && $this->cur_page != 1){ return $this->get_link($this->get_url(1),$this->first_page); } return "<span>$this->first_page</span>"; } /** * 獲取上一頁鏈接地址 */ public function get_prev_page(){ if ($this->cur_page > 1 && $this->cur_page !=1){ return $this->get_link($this->get_url($this->cur_page-1),$this->pre_page); } return '<span>'.$this->pre_page.'</span>'; } /** * 獲取下一頁鏈接地址 * @return string */ public function get_next_page(){ if ($this->cur_page < $this->total_page){ return $this->get_link($this->get_url($this->cur_page+1),$this->nex_page); } return '<span>'.$this->nex_page.'</span>'; } /** * 獲取...符號 * @return string */ public function get_ext(){ return '<span>...</span>'; } /** * 獲取尾頁地址 */ public function get_end_page(){ if ($this->cur_page < $this->total_page){ return $this->get_link($this->get_url($this->total_page),$this->end_page); } return '<span>'.$this->end_page.'</span>'; } /** * 中間的數字分頁 */ public function now_bar(){ if ($this->cur_page > $this->num_size){ $begin = $this->cur_page - $this->num_size; $end = $this->cur_page + $this->num_size; //判斷最后一頁是否大於總頁數 if ($end > $this->total_page){ //重新計算開始頁和結束頁 $begin = ($this->total_page - 2*$this->num_size > 0) ? $this->total_page - 2*$this->num_size : 1; //這里為什么用2*$this->num_size呢?因為當前頁前后有2個$this->num_size的間距,所以這里是2*$this->num_size $end = $this->total_page; } }else{ $begin = 1; $end = 2*$this->num_size+1;//此處的2和上面已經解釋過了,+1是因為除了當前頁,前后還有2*$this->num_size的間距,所以總頁碼條數為2*$this->num_size+1 } $page_html=''; for ($i=$begin;$i<=$end;$i++){ if ($i == $this->cur_page){ $page_html .= '<span class="disabled">'.$i.'</span>'; }else{ $page_html .= $this->get_link($this->get_url($i),$i); } } return $page_html; } /** * 輸出分頁碼 */ public function show_page(){ $show_page = ''; $ext = ($this->cur_page>$this->num_size) ? $this->get_ext() : ''; $show_page.= $this->show_total_row(); $show_page.= $this->show_total_page(); $show_page.= $this->get_first_page(); $show_page.= $this->get_prev_page(); $show_page.= $ext; $show_page.= $this->now_bar(); $show_page.= $ext; $show_page.= $this->get_next_page(); $show_page.= $this->get_end_page(); return $show_page; } /** * 獲取分頁地址 xxx.com/index/3 * @param $i */ public function get_url($i){ return $this->base_url.'/'.$i; } /** * 獲取分頁完整鏈接 * @param $url */ public function get_link($url,$text){ if ($this->params) $url.=$this->params; return "<a href='$url'>$text</a>"; } /** * 返回總條數 * @return string */ public function show_total_row(){ return "共{$this->total}條"; } /** * 返回總頁數 */ public function show_total_page(){ return "共{$this->total_page}頁"; } }
前台頁面:
<?php include_once ('Mypage.php'); $host = '127.0.0.1'; $db_user = 'root'; $db_pass = 'root'; $db_name = 'article'; $link = new mysqli($host,$db_user,$db_pass); if (mysqli_connect_errno()){ printf("數據庫鏈接失敗了:".mysqli_connect_error()); exit(); } if ( ! $link->select_db($db_name)){ printf("你選擇的數據庫{$db_name}不存在"); exit(); } $page_size = 10; //p($url); //p(__DIR__); //p(__FILE__); //p(pathinfo(__FILE__, PATHINFO_BASENAME)); $condition = [ 'age'=>20, 'city'=>40 ]; //p(make_url($condition)); //$cur_page = isset($_GET['page']) ? $_GET['page'] : 1; $cur_page = get_url_param(parse_url($_SERVER['REQUEST_URI'])['path'],4); //假如url鏈接為,http://xxx.net/fenye.php/index/list/6?age=20&city=40 //我這邊以平常開發常用的url鏈接為例,我這個鏈接只有兩層index/list,如果是tp的話無路由鏈接一般為index/index/list(模塊/控制器/方法) $sql = "SELECT COUNT(1) nums FROM py_information"; $query = $link->query($sql); $row = $query->fetch_assoc(); $total = $row['nums'];//數據總條數 $page_config=[ 'cur_page'=>$cur_page, 'total'=>$total, 'page_size'=>$page_size, 'base_url'=>'/fenye.php/index/list', 'num_link'=>2, 'params'=>make_url($condition) ]; $mypage = new Mypage($page_config); $start = ($cur_page-1)*$page_size;//按照分頁規律計算出數據起始條數 $sql = "SELECT inf_id,inf_title FROM article LIMIT $start,$page_size"; if ($result = $link->query($sql)){ $arr = []; while ($row = $result->fetch_assoc()){ $arr[] = $row; } } /** * 獲取url中的分段數據 * @param $url 鏈接url * @param $seg 獲取url中的第幾段 */ function get_url_param($url,$seg){ $url = explode('/',$url); return isset($url[$seg]) ? $url[$seg] : 1; } /** * 組合url參數 ?id=2&city=3 * @param array $data */ function make_url(array $data=[]){ $link = '?'; $suffix = '&'; foreach ($data as $key=>$val){ $link .= $key.'='.$val.$suffix; } return trim($link,$suffix); } function p($data){ echo '<pre>'; print_r($data); echo '</pre>'; }; ?> <html lang="en"> <head> <meta charset="utf-8"> <title>充值</title> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"> <style type="text/css"> .page_nav { font-family: Simsun; line-height:normal;text-align: right;margin-top: 10px;overflow: hidden;zoom: 1;text-align:center} .page_nav a,.page_nav span,.page_nav input{display:inline-block;line-height:23px;padding:0 10px;border:1px solid #ccc;background-color:#fff; text-decoration:none;color:#666;margin-right:5px;zoom: 1;} .page_nav input{height: 23px;line-height: 23px;padding: 0;zoom: 1; font:12px/16px;font-family: Simsun;zoom: 1;_margin-bottom:-4px;} .page_nav a:hover,.page_nav span.pg_curr{color:#fff !important;background-color:#C00;border-color:#be0d11 #be0d11 #9a0307; text-decoration:none;} .disabled{ background: #C00 !important; color: #fff !important;} </style> </head> <body> <table> <thead> <th>id</th> <th>標題</th> </thead> <?php foreach($arr as $key=>$val):?> <tr> <td><?php echo $val['inf_id'];?></td> <td><?php echo $val['inf_title'];?></td> </tr> <?php endforeach;?> </table> <div class="page_nav" style="margin: 15px;"> <?=$mypage->show_page();?> </div> </body> </html>
你可以將此分頁類移植到tp或者CI等其它框架中去。
數據庫你可以隨便找一個,這里我就不提供了,感謝大家的閱讀,有不對的地方請指正。
另外我在github上面開源了一些項目,覺得有用的給個star,地址:https://github.com/sunjiaqiang