<!-- /* Font Definitions */ @font-face {font-family:宋体; panose-1:2 1 6 0 3 1 1 1 1 1; mso-font-alt:SimSun; mso-font-charset:134; mso-generic-font-family:auto; mso-font-pitch:variable; mso-font-signature:3 135135232 16 0 262145 0;} @font-face {font-family:"/@宋体"; panose-1:2 1 6 0 3 1 1 1 1 1; mso-font-charset:134; mso-generic-font-family:auto; mso-font-pitch:variable; mso-font-signature:3 135135232 16 0 262145 0;} /* Style Definitions */ p.MsoNormal, li.MsoNormal, div.MsoNormal {mso-style-parent:""; margin:0cm; margin-bottom:.0001pt; text-align:justify; text-justify:inter-ideograph; mso-pagination:none; font-size:10.5pt; mso-bidi-font-size:12.0pt; font-family:"Times New Roman"; mso-fareast-font-family:宋体; mso-font-kerning:1.0pt;} h1 {mso-margin-top-alt:auto; margin-right:0cm; mso-margin-bottom-alt:auto; margin-left:0cm; mso-pagination:widow-orphan; mso-outline-level:1; font-size:24.0pt; font-family:宋体; mso-bidi-font-family:宋体; font-weight:bold;} a:link, span.MsoHyperlink {color:blue; text-decoration:underline; text-underline:single;} a:visited, span.MsoHyperlinkFollowed {color:purple; text-decoration:underline; text-underline:single;} p {mso-margin-top-alt:auto; margin-right:0cm; mso-margin-bottom-alt:auto; margin-left:0cm; mso-pagination:widow-orphan; font-size:12.0pt; font-family:宋体; mso-bidi-font-family:宋体;} /* Page Definitions */ @page {mso-page-border-surround-header:no; mso-page-border-surround-footer:no;} @page Section1 {size:595.3pt 841.9pt; margin:72.0pt 90.0pt 72.0pt 90.0pt; mso-header-margin:42.55pt; mso-footer-margin:49.6pt; mso-paper-source:0; layout-grid:15.6pt;} div.Section1 {page:Section1;} -->
1 、前言
分页 显 示是一种非常常见的浏览和显示大量数据的方法,属于web 编程中最常处理的事件之一。对于web 编程的老手来说,编写这种代码实在是和呼吸一样自然,但是 对于初学者来说,常常对这个问题摸不着头绪,因此特地撰写此文对这个问题进行详细的讲解,力求让看完这篇文章的朋友在看完以后对于分页显示的原理和实现方 法有所了解。本文适合初学者阅读,所有示例代码均使用php 编写。
2 、原理
所谓分页显示,也就是将数据库 中的结果集人为的分成一段一段的来显示,这里需要两个初始的参数:
每页多少条记录($PageSize )?
当前是第几页($CurrentPageID )?
现在只要再给我一个结果集,我就可以显示某段特定的结果出来。
至于其他的参数,比如:上一页($PreviousPageID )、下一页($NextPageID )、总页数($numPages )等等,都可以根据前边这几个东西得到。
以mysql 数据库为例,如果要从表内截取某段内容,sql 语句可以用:select * from table limit offset, rows 。看看下面一组sql 语句,尝试一下发现其中的规率。
前10 条记录:select * from table limit 0,10
第11 至20 条记录:select * from table limit 10,10
第21 至30 条记录:select * from table limit 20,10
……
这一组sql 语句其实就是当$PageSize=10 的时候取表内每一页数据的sql 语句,我们可以总结出这样一个模板:
select * from table limit ($CurrentPageID - 1) * $PageSize, $PageSize
拿这个模板代入对应的值和上边那一组sql 语句对照一下看看是不是那么回事。搞定了最重要的如何获取数据的问题以后,剩下的就仅仅是传递参数,构造合适的sql 语句然后使用php 从数据库内获取数据并显示了。以下我将用具体代码加以说明。
3 、简单代码
请详细阅读以下代码,自己调试运行一次,最好把它修改一次,加上自己的功能,比如搜索等等。
<?php
// 建立数据库连接
$link = mysql_connect("localhost", "mysql_user", "mysql_password ")
or die("Could not connect: " . mysql_error());
// 获取当前页数
if( isset($_GET['page']) ){
$page = intval( $_GET['page'] );
}
else{
$page = 1;
}
// 每页数量
$PageSize = 10;
// 获取总数据量
$sql = "select count(*) as amount from table";
$result = mysql_query($sql);
$row = mysql_fetch_row($result);
$amount = $row['amount'];
// 记算总共有多少页
if( $amount ){
if( $amount < $page_size ){ $page_count = 1; } // 如果总数据量小于$PageSize ,那么只有一页
if( $amount % $page_size ){ // 取总数据量除以每页数的余数
$page_count = (int)($amount / $page_size) + 1; // 如果有余数,则页数等于总数据量除以每页数的结果取整再加一
}else{
$page_count = $amount / $page_size; // 如果没有余数,则页数等于总数据量除以每页数的结果
}
}
else{
$page_count = 0;
}
// 翻页链接
$page_string = '';
if( $page == 1 ){
$page_string .= ' 第一页| 上一页|';
}
else{
$page_string .= '<a href=?page=1> 第一页</a>|<a href=?page='.($page-1).'> 上一页</a>|';
}
if( ($page == $page_count) || ($page_count == 0) ){
$page_string .= ' 下一页| 尾页';
}
else{
$page_string .= '<a href=?page='.($page+1).'> 下一页</a>|<a href=?page='.$page_count.'> 尾页</a>';
}
// 获取数据,以二维数组格式返回结果
if( $amount ){
$sql = "select * from table order by id desc limit ". ($page-1)*$page_size .", $page_size";
$result = mysql_query($sql);
while ( $row = mysql_fetch_row($result) ){
$rowset[] = $row;
}
}else{
$rowset []= array();
}
// 没有包含显示结果的代码,那不在讨论范围,只要用foreach 就可以很简单的用得到的二维数组来显示结果
?>
4 、OO 风格代码
以下代码中的数据库连接是使用的pear db 类进行处理
<?php
// FileName: Pager.class.php
// 分页类,这个类仅仅用于处理数据结构,不负责处理显示的工作
Class Pager
{
var $PageSize; // 每页的数量
var $CurrentPageID; // 当前的页数
var $NextPageID; // 下一页
var $PreviousPageID; // 上一页
var $numPages; // 总页数
var $numItems; // 总记录数
var $isFirstPage; // 是否第一页
var $isLastPage; // 是否最后一页
var $sql; //sql 查询语句
function Pager($option)
{
global $db;
$this->_setOptions($option);
// 总条数
if ( !isset($this->numItems) )
{
$res = $db->query($this->sql);
$this->numItems = $res->numRows();
}
// 总页数
if ( $this->numItems > 0 )
{
if ( $this->numItems < $this->PageSize ){ $this->numPages = 1; }
if ( $this->numItems % $this->PageSize )
{
$this->numPages= (int)($this->numItems / $this->PageSize) + 1;
}
else
{
$this->numPages = $this->numItems / $this->PageSize;
}
}
else
{
$this->numPages = 0;
}
switch ( $this->CurrentPageID )
{
case $this->numPages == 1:
$this->isFirstPage = true;
$this->isLastPage = true;
break;
case 1:
$this->isFirstPage = true;
$this->isLastPage = false;
break;
case $this->numPages:
$this->isFirstPage = false;
$this->isLastPage = true;
break;
default:
$this->isFirstPage = false;
$this->isLastPage = false;
}
if ( $this->numPages > 1 )
{
if ( !$this->isLastPage ) { $this->NextPageID = $this->CurrentPageID + 1; }
if ( !$this->isFirstPage ) { $this->PreviousPageID = $this->CurrentPageID - 1; }
}
return true;
}
/***
*
* 返回结果集的数据库连接
* 在结果集比较大的时候可以直接使用这个方法获得数据库连接,然后在类之外遍历,这样开销较小
* 如果结果集不是很大,可以直接使用getPageData 的方式获取二维数组格式的结果
* getPageData 方法也是调用本方法来获取结果的
*
***/
function getDataLink()
{
if ( $this->numItems )
{
global $db;
$PageID = $this->CurrentPageID;
$from = ($PageID - 1)*$this->PageSize;
$count = $this->PageSize;
$link = $db->limitQuery($this->sql, $from, $count); // 使用Pear DB::limitQuery 方法保证数据库兼容性
return $link;
}
else
{
return false;
}
}
/***
*
* 以二维数组的格式返回结果集
*
***/
function getPageData()
{
if ( $this->numItems )
{
if ( $res = $this->getDataLink() )
{
if ( $res->numRows() )
{
while ( $row = $res->fetchRow() )
{
$result[] = $row;
}
}
else
{
$result = array();
}
return $result;
}
else
{
return false;
}
}
else
{
return false;
}
}
function _setOptions($option)
{
$allow_options = array(
'PageSize',
'CurrentPageID',
'sql',
'numItems'
);
foreach ( $option as $key => $value )
{
if ( in_array($key, $allow_options) && ($value != null) )
{
$this->$key = $value;
}
}
return true;
}
}
?>
<?php
// FileName: test_pager.php
// 这是一段简单的示例代码,前边省略了使用pear db 类建立数据库连接的代码
require "Pager.class.php";
if ( isset($_GET['page']) )
{
$page = (int)$_GET['page'];
}
else
{
$page = 1;
}
$sql = "select * from table order by id";
$pager_option = array(
"sql" => $sql,
"PageSize" => 10,
"CurrentPageID" => $page
);
if ( isset($_GET['numItems']) )
{
$pager_option['numItems'] = (int)$_GET['numItems'];
}
$pager = @new Pager($pager_option);
$data = $pager->getPageData();
if ( $pager->isFirstPage )
{
$turnover = " 首页| 上一页|";
}
else
{
$turnover = "<a href='?page=1&numItems=".$pager->numItems."'> 首页</a>|< a href='?page=".$pager->PreviousPageID."&numItems=".$pager-> numItems."'> 上一页</a>|";
}
if ( $pager->isLastPage )
{
$turnover .= " 下一页| 尾页";
}
else
{
$turnover .= "<a href='?page=".$pager->NextPageID."&numItems=".$pager-> numItems."'> 下一页</a>|<a href='?page=".$pager->numPages."&numItems=".$pager-> numItems."'> 尾页</a>";
}
?>
需要说明的地方有两个:
这个类仅仅处理数据,并不负责处理显示,因为我觉得将数据的处理和结果的显示都放到一个类里边实在是有些勉强。显示的时候情况和要求多变,不如自己根据类给出的结果处理,更好的方法是根据这个Pager 类继承一个自己的子类来显示不同的分页,比如显示用户分页列表可以:
<?php
Class MemberPager extends Pager
{
function showMemberList()
{
global $db;
$data = $this->getPageData();
// 显示结果的代码
// ......
}
}
/// 调用
if ( isset($_GET['page']) )
{
$page = (int)$_GET['page'];
}
else
{
$page = 1;
}
$sql = "select * from members order by id";
$pager_option = array(
"sql" => $sql,
"PageSize" => 10,
"CurrentPageID" => $page
);
if ( isset($_GET['numItems']) )
{
$pager_option['numItems'] = (int)$_GET['numItems'];
}
$pager = @new MemberPager($pager_option);
$pager->showMemberList();
?>
第二个需要说明的地方就是不同数据库的兼容性,在不同的数据库里截获一段结果的写法是不一样的。
mysql: select * from table limit offset, rows
pgsql: select * from table limit m offset n
......
所以要在类里边获取结果的时候需要使用pear db 类的limitQuery 方法。
ok ,写完收功,希望花时间看完这些文字的你不觉得是浪费了时间。
另一个EXAMPLE “
1. <?php
2. class SubPages{
3.
4. private $each_disNums;// 每页显示的条目数
5. private $nums;// 总条目数
6. private $current_page;// 当前被选中的页
7. private $sub_pages;// 每次显示的页数
8. private $pageNums;// 总页数
9. private $page_array = array();// 用来构造分页的数组
10. private $subPage_link;// 每个分页的链接
11. private $subPage_type;// 显示分页的类型
12. /*
13. __construct 是SubPages 的构造函数,用来在创建类的时候自动运行.
14. @$each_disNums 每页显示的条目数
15. @nums 总条目数
16. @current_num 当前被选中的页
17. @sub_pages 每次显示的页数
18. @subPage_link 每个分页的链接
19. @subPage_type 显示分页的类型
20.
21. 当@subPage_type=1 的时候为普通分页模式
22. example : 共4523 条记录, 每页显示10 条, 当前第1/453 页 [ 首页] [ 上页] [ 下页] [ 尾页]
23. 当@subPage_type=2 的时候为经典分页样式
24. example : 当前第1/453 页 [ 首页] [ 上页] 1 2 3 4 5 6 7 8 9 10 [ 下页] [ 尾页]
25. */
26. function __construct($each_disNums,$nums,$current_page,$sub_pages,$subPage_link,$subPage_type){
27. $this->each_disNums=intval($each_disNums);
28. $this->nums=intval($nums);
29. if(!$current_page){
30. $this->current_page=1;
31. }else{
32. $this->current_page=intval($current_page);
33. }
34. $this->sub_pages=intval($sub_pages);
35. $this->pageNums=ceil($nums/$each_disNums);
36. $this->subPage_link=$subPage_link;
37. $this->show_SubPages($subPage_type);
38. //echo $this->pageNums."--".$this->sub_pages;
39. }
40.
41.
42. /*
43. __destruct 析构函数,当类不在使用的时候调用,该函数用来释放资源。
44. */
45. function __destruct(){
46. unset($each_disNums);
47. unset($nums);
48. unset($current_page);
49. unset($sub_pages);
50. unset($pageNums);
51. unset($page_array);
52. unset($subPage_link);
53. unset($subPage_type);
54. }
55.
56. /*
57. show_SubPages 函数用在构造函数里面。而且用来判断显示什么样子的分页
58. */
59. function show_SubPages($subPage_type){
60. if($subPage_type == 1){
61. $this->subPageCss1();
62. }elseif ($subPage_type == 2){
63. $this->subPageCss2();
64. }
65. }
66.
67.
68. /*
69. 用来给建立分页的数组初始化的函数。
70. */
71. function initArray(){
72. for($i=0;$i<$this->sub_pages;$i++){
73. $this->page_array[$i]=$i;
74. }
75. return $this->page_array;
76. }
77.
78.
79. /*
80. construct_num_Page 该函数使用来构造显示的条目
81. 即使:[1][2][3][4][5][6][7][8][9][10]
82. */
83. function construct_num_Page(){
84. if($this->pageNums < $this->sub_pages){ // 假如总页数小于每次显示的页数
85. $current_array=array();
86. for($i=0;$i<$this->pageNums;$i++){
87. $current_array[$i]=$i+1; // 数组的值为所有页数
88. }
89. }else{
90. $current_array=$this->initArray(); // 先初使化
91. if($this->current_page <= 3){ // 假如当前页数为1-3 页,显示的是所要显示的页数
92. for($i=0;$i<count($current_array);$i++){
93. $current_array[$i]=$i+1;
94. }
95. }elseif ($this->current_page <= $this->pageNums && $this->current_page > $this->pageNums - $this->sub_pages + 1 ){ //
96. for($i=0;$i<count($current_array);$i++){
97. $current_array[$i]=($this->pageNums)-($this->sub_pages)+1+$i;
98. }
99. }else{
100. for($i=0;$i<count($current_array);$i++){
101. $current_array[$i]=$this->current_page-2+$i;
102. }
103. }
104. }
105.
106. return $current_array;
107. }
108.
109. /*
110. 构造普通模式的分页
111. 共4523 条记录, 每页显示10 条, 当前第1/453 页 [ 首页] [ 上页] [ 下页] [ 尾页]
112. */
113. function subPageCss1(){
114. $subPageCss1Str="";
115. $subPageCss1Str.=" 共".$this->nums." 条记录,";
116. $subPageCss1Str.=" 每页显示".$this->each_disNums." 条,";
117. $subPageCss1Str.=" 当前第".$this->current_page."/".$this->pageNums." 页 ";
118. if($this->current_page > 1){
119. $firstPageUrl=$this->subPage_link."1";
120. $prewPageUrl=$this->subPage_link.($this->current_page-1);
121. $subPageCss1Str.="[<a href='$firstPageUrl'> 首页</a>] ";
122. $subPageCss1Str.="[<a href='$prewPageUrl'> 上一页</a>] ";
123. }else {
124. $subPageCss1Str.="[ 首页] ";
125. $subPageCss1Str.="[ 上一页] ";
126. }
127.
128. if($this->current_page < $this->pageNums){
129. $lastPageUrl=$this->subPage_link.$this->pageNums;
130. $nextPageUrl=$this->subPage_link.($this->current_page+1);
131. $subPageCss1Str.=" [<a href='$nextPageUrl'> 下一页</a>] ";
132. $subPageCss1Str.="[<a href='$lastPageUrl'> 尾页</a>] ";
133. }else {
134. $subPageCss1Str.="[ 下一页] ";
135. $subPageCss1Str.="[ 尾页] ";
136. }
137.
138. echo $subPageCss1Str;
139.
140. }
141.
142.
143. /*
144. 构造经典模式的分页
145. 当前第1/453 页 [ 首页] [ 上页] 1 2 3 4 5 6 7 8 9 10 [ 下页] [ 尾页]
146. */
147. function subPageCss2(){
148. $subPageCss2Str="";
149. $subPageCss2Str.=" 当前第".$this->current_page."/".$this->pageNums." 页 ";
150.
151.
152. if($this->current_page > 1){
153. $firstPageUrl=$this->subPage_link."1";
154. $prewPageUrl=$this->subPage_link.($this->current_page-1);
155. $subPageCss2Str.="[<a href='$firstPageUrl'> 首页</a>] ";
156. $subPageCss2Str.="[<a href='$prewPageUrl'> 上一页</a>] ";
157. }else {
158. $subPageCss2Str.="[ 首页] ";
159. $subPageCss2Str.="[ 上一页] ";
160. }
161.
162. $a=$this->construct_num_Page();
163. for($i=0;$i<count($a);$i++){
164. $s=$a[$i];
165. if($s == $this->current_page ){
166. $subPageCss2Str.="[<span style='color:red;font-weight:bold;'>".$s."</span>]";
167. }else{
168. $url=$this->subPage_link.$s;
169. $subPageCss2Str.="[<a href='$url'>".$s."</a>]";
170. }
171. }
172.
173. if($this->current_page < $this->pageNums){
174. $lastPageUrl=$this->subPage_link.$this->pageNums;
175. $nextPageUrl=$this->subPage_link.($this->current_page+1);
176. $subPageCss2Str.=" [<a href='$nextPageUrl'> 下一页</a>] ";
177. $subPageCss2Str.="[<a href='$lastPageUrl'> 尾页</a>] ";
178. }else {
179. $subPageCss2Str.="[ 下一页] ";
180. $subPageCss2Str.="[ 尾页] ";
181. }
182. echo $subPageCss2Str;
183. }
184. }
185. ?>