我们在项目开发的过程中避免不了使用分页功能,拿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&amp;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

PHP+Mysql实现分页的更多相关文章

  1. MySQL的分页优化

    今天下午,帮同事重写了一个MySQL SQL语句,该SQL语句涉及两张表,其中一张表是字典表(需返回一个字段),另一张表是业务表(本身就有150个字段,需全部返回),当然,字段的个数是否合理在这里不予 ...

  2. oracle sqlserver mysql数据库分页

    1.Mysql的limit用法 在我们使用查询语句的时候,经常要返回前几条或者中间某几行数据,这个时候怎么办呢?不用担心,mysql已经为我们提供了这样一个功能. SELECT * FROM tabl ...

  3. MySQL的分页

    有朋友问: MySQL的分页似乎一直是个问题,有什么优化方法吗?网上看到网上推荐了一些分页方法,但似乎不太可行,你能点评一下吗? 方法1: 直接使用数据库提供的SQL语句 ---语句样式: MySQL ...

  4. MySql通用分页存储过程

    MySql通用分页存储过程 1MySql通用分页存储过程 2 3过程参数 4p_cloumns varchar(500),p_tables varchar(100),p_where varchar(4 ...

  5. Statement和PreparedStatement的特点 MySQL数据库分页 存取大对象 批处理 获取数据库主键值

    1 Statement和PreparedStatement的特点   a)对于创建和删除表或数据库,我们可以使用executeUpdate(),该方法返回0,表示未影向表中任何记录   b)对于创建和 ...

  6. mysql 查询优化~ 分页优化讲解

    一 简介:今天咱们来聊聊mysql的分页查询二 语法     LIMIT [offset,] rows     offset是第多少条     rows代表多少条之后的行数    性能消耗    se ...

  7. mysql实现分页的几种方式

    mysql实现分页的几种方式: 第一种:使用框架自带的pageable来进行分页 package com.cellstrain.icell.repository.repositoryImpl; imp ...

  8. mybatis对mysql进行分页

    Mybatis对mysql数据库分页 在generator中增加插件,下载地址http://download.csdn.net/detail/shunlongjin/6937045 <plugi ...

  9. atitit。mssql sql server 转换mysql 及 分页sql ast的搭建

    atitit.mssql sql server 转换mysql  及 分页sql ast的搭建 1. 主要的的转换::函数的转换,分页的转换 1 2. 思路::mssql sql >>as ...

  10. oracle 的分页与 mySQL'的分页转化

    oracle 分页:  关键字ROWNUM SELECT EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO FROM ( SELECT A.*, ...

随机推荐

  1. 新装centos 6.5 基本配置

    开机自动联网 vi /etc/sysconfig/network-scripts/ifcfg-eth0; 将ONBOOT=no,改为ONBOOT=yes,保存退出 开机直接进入命令行模式 vi /et ...

  2. bzoj4300 绝世好题 【dp】By cellur925

    题目描述: 给定一个长度为\(n\)的数列\(a\),求\(a\)的子序列\(b\)的最长长度,满足bi&bi-1!=0(\(2<=i<=len\)). 90分做法: 并没有部分分 ...

  3. [软件工程基础]2017.11.04 第八次 Scrum 会议

    具体事项 项目交接燃尽图 每人工作内容 成员 已完成的工作 计划完成的工作 工作中遇到的困难 游心 #10 搭建可用的开发测试环境:#9 阅读分析 PhyLab 后端代码与文档:#8 掌握 Larav ...

  4. python库使用整理

    1. 环境搭建 l  Python安装包:www.python.org l  Microsoft Visual C++ Compiler for Python l  pip(get-pip.py):p ...

  5. 转 Oracle Cluster Health Monitor(CHM)简介

    Cluster Health Monitor(以下简称CHM)是一个Oracle提供的工具,用来自动收集操作系统的资源(CPU.内存.SWAP.进程.I/O以及网络等)的使用情况.CHM会每秒收集一次 ...

  6. #113. 【UER #2】手机的生产

    链接:http://uoj.ac/problem/113 由于电信技术的发展,人人都可以通过手机互相联系. 有一位电信大佬最近想生产一大批手机,然而从生产线上一台一台地生产实在太慢了,于是他想出了一个 ...

  7. laravel 5.5 oauth2.0 跨域问题解决方案

    一.laravel-Cors 安装 在终端执行安装命令如下: composer require barryvdh/laravel-cors 添加服务提供商 在Laravel配置文件app.php的pr ...

  8. iOS --runtime理解

    iOS~runtime理解 Runtime是想要做好iOS开发,或者说是真正的深刻的掌握OC这门语言所必需理解的东西.最近在学习Runtime,有自己的一些心得,整理如下,一为 查阅方便二为 或许能给 ...

  9. Linux自带-系统级性能分析工具 — Perf(转)

    https://blog.csdn.net/zhangskd/article/details/37902159/

  10. sqlite的应用

    对于Android平台来说,系统内置了丰富的API来供开发人员操作SQLite,我们可以轻松的完成对数据的存取.下面就向大家介绍一下SQLite常用的操作方法.本篇文章主要用到SQLiteDataba ...