看大家都搞分页类,忍不住把我半年前的东西抛出来了
时间:2007-02-17 来源:PHP爱好者
[b:d3677449b5]由于CU代码转换有问题,copy下的源码无法运行,现提供代码直接下载。
请访问:
http://www.longnetpro.com/demo
http://longnetpro.xicp.net/demo
[/b:d3677449b5][/size:d3677449b5]
看到大家都搞分页类,弄得心痒痒的,就忍不住把我半年前写的一个分页类修改了一下,也抛出来了。
说明:
这是个包,内含几个分页类,是半年前写的,今天做了一些修正。这次在核心代码不变的情况下,主要对扩展性与易用性上面做了改进。
这个包是按照OO的思想,按逻辑层次设计的,共有三层继承。基类为PageNavigator,其子类为PageCustomizedNavigator,下一级子类为PageDefaultNavigator,再下级子类就由用户根据需求自定义了。
继承了我一贯的OO作风,一个类要充分发挥它的作用,不相关的内容坚决不放在一个类中,业务逻辑与显示逻辑严格分离,永远要考虑类的封装性(接口的友好性)与可持续发展能力(类可扩展能力),这个包中的类基本遵循以上原则。这些类不但提供给程序员友好的扩展接口,使之功能更多更强,也可以直接使用它的默认形式。你将会在我给的例子中看到,如何将默认的英文输出用简单的资源重定义即变为全中文输出,你甚至可以在不改变任何核心代码的情况下改变输出文字——只简单重载一下构造函数或是用set***方法从外部设置——显示文字绝不会出现在核心代码之中。此类对输入进行严格检查,自动容错,自动检测输入有效性,保证分页都在有效的范围之内。有多个自动显示选项,可以设置是否根据情况显示上页下页等或是强制显示。特别加了一个“跳到第x页”的FORM,可手工输入页号进行跳转,并用JS进行有效性检测。
显示内容:
分三大部分,一是信息部分,二是列表部分,三是跳转部分。下面简单说一下三个部分。
信息部分:显示共有几条记录,共多少页,每页几条记录。
列表部分:即为带URL的页码号,它又分为“首页”、“前*页”、“上一页”、连续的页码、“下一页”、“后*页”、“末页”这七个部分,每一个部分在类中都有一个方法得到这个部分的字符串表达,每个这类方法都是protected的,如果需要可被子类重载——如果你需要定制自己的显示方式,可重载它们,在一般情况下,默认的方式通过设置不同的参数已足够用了(不需要你对代码做任何修改,只需设置参数即可)。
跳转部分:这个部分是个FORM,可以输入页码直接跳转,用JS代码作有效性检测并跳转到相应的页面。
三个类的简要介绍:
PageNavigator:基类,纯计算类,只需输入总记录数与当前页号,则根据参数算出其它所有必要数据(包括记录的偏移量,这个值可以用在MYSQL中的LIMIT中,还有其它一些数据)。
PageCustomizedNavigator:PageNavigator的子类,根据计算出来的数据及以有参数与资源变量生成上面所述三个部分的字符串表达,其中列表部分会带URL。这个类中所有的get***Output方法都是protected,可以被其子类重载,以便定制你自己的表示方式。最后一个outputAll方法是输出默认形式的列表。
PageDefaultNavigator:这个类在PageCustomizedNavigator上继承。它没有具体的操作方法,只是重载了一下父类的构造函数,装载了一个英文资源与一些默认的参数,如果调用这个类的outputAll方法就会按默认方式输出列表信息。
最后是关于测试文件的说明:
这个测试意在说明如何定制列表的输出形式。可以看到,仅通过重载PageDefaultNavigator类或是PageCustomizedNavigator类的构造函数,将英文对应的翻译成中文,在不用修改任何核心代码的情况下,就将整个列表用中文显示出来。同时,代码的调用也极为简单,无非就是几步:创建对象,设置总记录数,调用prepare方法进行准备,调用calculate方法计算出所有数据,然后设置显示参数(或直接用默认值,可选),最后就是输出了。如果你自己做好了一个类,可以把它单独放到一个文件中,并在这个类中加入一个方法使以上的前几个步骤合在这个方法中(比如加一个initialize方法),以达到更好的封装,使调用更为简洁,接口更为清晰。当然,仅用重载构造函数或是用setResource或是setOptions方法使用外部资源只是定制输出列表的一个最基本方法,更高级的是重载一些保护的(protected)方法。由于每个方法的功能非常单一,你完全不用担心对些方法的任何修改会影响到其它的功能——除非你自己人为的在一个方法中去做与它本身毫无关系的事。如果你不想输出所有的信息,你可以在从基类派生出来的你自己的类中加入一个输出方法以取代outputAll方法,或是干脆重载它,反正输出的各个部分都是现成的,你的输出方法只不过是取你要用的那些部分罢了。如果你愿意,不妨自己加几个参数进行控制。
文件:
本来这几个文件是我的库中的几个文件,与其它类库或是函数库有关联,单独拿出来是运行不了的。今天作了一下修改,可以独立运行了。
文件只有两个,一个是包所在的文件pagenavigator.class.php,这次有些简短的英文注释,希望我的英语不是太滥,大家还能看得懂——不过我想从程序上来说应该还是比较易懂的。第二个还是老规矩,test.php,测试文件,放在一个目录下,可以运行。当然,没有详细debug,可能会有一些问题,不过用OO编程,维护起来的确容易多了,写程序中还好没有碰到太多逻辑的BUG。
另外,我原来一直强调,分页类就是分页类,不应当与数据库搞在一起,因此我这个包中的类没有一个是与数据库有关的,连一个SQL语句都没有——我个人认为,如果在分页类里放与数据库有关的内容,只能说明写程序的人对OO还没有理解清楚。但是不是这个包就不能与数据库结合用呢?肯定不是。其实在TEST中,就可以把for循环改成数据库循环即可。理论上说分页类与数据库没有什么过多直接的关系,因为分页类中唯一需要知道的外部数据就是总记录数,与数据库有关的代码只负责把数据库中所需要显示的数据取出显示就行了,这个过程与分页类是没有任何关系的(除了在查询前需要从分页类得到LIMIT的两上参数外)。
具体的内容还是看一下代码吧。
最后说一句:这个说明是直接打出来的,没有打草稿,因此可能会出现语句不通或是语法错误或是打字错误等等,就请大家包涵一下了。后面分两帖帖上类代码与测试代码。
longnetpro 回复于:2004-05-16 11:12:04 pagenavigator.class.php
[code:1:204da7b438]
<?php
if(!defined('_IN_APP')) exit;
define('PAGE_RPP_DEF', 10);
define('PAGE_PPL_DEF', 10);
class PageNavigator
{
var $recordsPerPage = PAGE_RPP_DEF; // how many records per page, default 10
var $pagesPerList = PAGE_PPL_DEF; // how many pages per list, default 10
var $totalRecords = 0; // number of all records
var $currentPage = 1; // current page number. 1 based(first number is 1)
var $currentList = 1; // current list number. 1 based
var $totalPages = 0; // number of all pages.
var $totalLists = 0; // number of all lists.
var $recordOffset = 0; // offset of the first record in the current page. 0 based
var $pageOffset = 0; // offset of the first page in the current list. 0 based
var $recordsInPage = 0; // number of records in current page.
var $pagesInList = 0; // number of pages in current list.
var $previousPages = 0; // number of the previous pages in the list
var $nextPages = 0; // number of the next pages in the list
function setParameter($recordsPerPage = 10, $pagesPerList = 10){
$this->recordsPerPage = intval($recordsPerPage);
$this->pagesPerList = intval($pagesPerList);
}
function setTotalRecords($totalRecords){
$this->totalRecords = intval($totalRecords);
}
// $currentPage: current page number, if the value is -1 means the last page
// $totalRecords: number of all records, if the value is -1 means using the
// stored one.
function calculate($currentPage = 1, $totalRecords = -1){
if ($totalRecords >= 0)
$this->totalRecords = intval($totalRecords);
if ($this->totalRecords <= 0)
return false;
$tr = $this->totalRecords;
$rpp = $this->recordsPerPage;
$ppl = $this->pagesPerList;
$tp = intval(ceil($tr / $rpp));
$tl = intval(ceil($tp / $ppl));
$cp = ($currentPage > 0 || $currentPage == -1)? $currentPage : 1;
$cp = ($cp == -1 || $cp > $tp)? $tp : $cp;
$cl = intval(ceil($cp / $ppl));
$ro = ($cp - 1) * $rpp;
$po = ($cl - 1) * $ppl;
$rip = ($cp == $tp)? ($tr % $rpp) : $rpp;
$pil = ($cl == $tl)? ($tp % $ppl) : $ppl;
$this->previousPages = ($cl <= 1)? 0 : $ppl;
if ($cl == $tl){
$this->nextPages = 0;
}else if ($cl >=1 && $cl == $tl - 1){
$this->nextPages = $tp % $ppl;
}else{
$this->nextPages = $ppl;
}
$this->currentPage = $cp;
$this->currentList = $cl;
$this->totalPages = $tp;
$this->totalLists = $tl;
$this->recordOffset = $ro;
$this->pageOffset = $po;
$this->recordsInPage = $rip;
$this->pagesInList = $pil;
return true;
}
}
// ----------------------------------------------------------------------------
define('PAGE_AUTO_NONE', 0);
define('PAGE_AUTO_FIRST_LAST', 1);
define('PAGE_AUTO_PREV_NEXT', 2);
define('PAGE_AUTO_FORWARD_BACKWARD', 4);
define('PAGE_AUTO_PAGE', 8);
define('PAGE_AUTO_GOTO', 16);
define('PAGE_AUTO_LIST_ALL', PAGE_AUTO_FIRST_LAST + PAGE_AUTO_PREV_NEXT +
PAGE_AUTO_FORWARD_BACKWARD + PAGE_AUTO_PAGE);
define('PAGE_AUTO_ALL', PAGE_AUTO_LIST_ALL + PAGE_AUTO_GOTO);
class PageCustomizedNavigator extends PageNavigator
{
var $resource = null;
var $options = null;
function PageCustomizedNavigator(){
$this->__construct();
}
function __construct(){
$this->resource = array();
$this->options = array();
}
function setResource($resource){
$this->resource =& $resource;
}
function setOptions($options){
if (!is_array($options)) return;
$this->options = $options;
}
function setOption($option, $value){
$this->options[$option] = $value;
}
function setAutoDisplay($option = PAGE_AUTO_LIST_ALL, $disabled = false){
if (!isset($this->options['auto_display']))
return;
if ($disabled){
$this->options['auto_display'] &= ~$option;
}else{
$this->options['auto_display'] |= $option;
}
}
// public
function prepare(){
$rpp = 0;
if (isset($this->options['records_per_page'])){
$rpp = intval($this->options['records_per_page']);
}
if ($rpp == 0) $rpp = PAGE_RPP_DEF;
$ppl = 0;
if (isset($this->options['pages_per_list'])){
$ppl = intval($this->options['pages_per_list']);
}
if ($ppl == 0) $ppl = PAGE_PPL_DEF;
$this->setParameter($rpp, $ppl);
}
// private
function _validate_page_number($page_number){
$pn = intval($page_number);
if ($pn < 1) $pn = 1;
if ($pn > $this->totalPages) $pn = $this->totalPages;
return $pn;
}
// private
function _validate_list_number($list_number){
$ln = intval($list_number);
if ($ln < 1) $ln = 1;
if ($ln > $this->totalLists) $ln = $this->totalLists;
return $ln;
}
// protected method, may be overriden by subclasses
function updateHref($page_number = 1){
$page_number = $this->_validate_page_number($page_number);
$href = sprintf($this->options['href_pattern'], $page_number);
return $href;
}
// protected method, may be overriden by subclasses
function getLink($page_number, $text){
$href = $this->updateHref($page_number);
$extra = $this->options['anchor_extra'];
if ($extra != '') $extra = ' '.$extra;
$link = '<a href="'.$href.'"'.$extra.'>'.$text.'</a>';
return $link;
}
// protected method, may be overriden by subclasses
function makeLink(&$text, $page_number, $list_number = -1){
if ($page_number == $this->currentPage) return false;
if ($list_number > 0 && $list_number == $this->currentList) return false;
$text = $this->getLink($page_number, $text);
return true;
}
// {{{ BEGIN Protected get***Output Methods
// protected method, may be overriden
// if not be overriden, using default processing
function getInfoOutput(){
$info = sprintf($this->resource['info'],
$this->totalRecords, $this->totalPages, $this->recordsPerPage);
return $info;
}
function getFirstOutput($opt_auto){
$num = $this->_validate_page_number(1);
$first = sprintf($this->resource['first'], $num);
if ($this->makeLink($first, $num) || ($opt_auto & PAGE_AUTO_FIRST_LAST) == 0)
return $first;
return '';
}
function getLastOutput($opt_auto){
$num = $this->_validate_page_number($this->totalPages);
$last = sprintf($this->resource['last'], $num);
if ($this->makeLink($last, $num) || ($opt_auto & PAGE_AUTO_FIRST_LAST) == 0)
return $last;
return '';
}
function getPreviousOutput($opt_auto){
$num = $this->_validate_page_number($this->pageOffset);
$lnum = $this->_validate_list_number($this->currentList - 1);
$prev = sprintf($this->resource['prev'], $num, $this->previousPages);
if ($this->makeLink($prev, $num, $lnum) || ($opt_auto & PAGE_AUTO_PREV_NEXT) == 0)
return $prev;
return '';
}
function getNextOutput($opt_auto){
$num = $this->_validate_page_number($this->pageOffset + $this->pagesInList + 1);
$lnum = $this->_validate_list_number($this->currentList + 1);
$next = sprintf($this->resource['next'], $num, $this->nextPages);
if ($this->makeLink($next, $num, $lnum) || ($opt_auto & PAGE_AUTO_PREV_NEXT) == 0)
return $next;
return '';
}
function getBackwardOutput($opt_auto){
$num = $this->_validate_page_number($this->currentPage - 1);
$backward = sprintf($this->resource['backward'], $num);
if ($this->makeLink($backward, $num) || ($opt_auto & PAGE_AUTO_FORWARD_BACKWARD) == 0)
return $backward;
return '';
}
function getForwardOutput($opt_auto){
$num = $this->_validate_page_number($this->currentPage + 1);
$forward = sprintf($this->resource['forward'], $num);
if ($this->makeLink($forward, $num) || ($opt_auto & PAGE_AUTO_FORWARD_BACKWARD) == 0)
return $forward;
return '';
}
function getListOutput(){
$p_sep = $this->options['list_seperator'];
$page = '';
for ($i = $this->pageOffset + 1, $j = 0; $j < $this->pagesInList; $i++, $j++){
$link = sprintf($this->resource['page'], $i);
if (!$this->makeLink($link, $i))
$link = sprintf($this->resource['current_page'], $i);
$page .= $link.$p_sep;
}
if ($p_sep != '') $page = substr($page, 0, - strlen($p_sep));
return $page;
}
function _filter_error_message($message = ''){
$tr = array("rn" => "n", "r" => "n");
$message = strtr($message, $tr);
$message = str_replace("n", 'n', $message);
return $message;
}
function getscriptOutput(){
$err1 = $this->_filter_error_message($this->err_msg[1]);
$err2 = $this->_filter_error_message($this->err_msg[2]);
$script = <<< EOF
<script language="Javascript" type="text/Javascript">
<!--
var errmsg = new Array();
errmsg[1] = '$err1';
errmsg[2] = '$err2';
function gotoPage(theform, currentpage, maxpages, urlpattern, se){
var i = theform.txtGotoPage.value;
var errno = 0;
if (i.search(/^[0-9]+$/) == -1){
errno = 1;
} else {
i = parseInt(i);
if (i > maxpages){
errno = 2;
} else {
var regex = '/(b'+se+')'+'@(&|$)/';
eval('var se0 = ' + regex + ';');
var s = urlpattern.replace(se0, '$1'+i+'$2');
self.location.href = s;
return;
}
}
if (errno != 0){
window.alert(errmsg[errno]);
theform.txtGotoPage.value = currentpage;
theform.txtGotoPage.focus();
}
}
// -->
</script>
EOF;
return $script;
}
function getGotoOutput(){
static $scriptAlreadyOut = false;
$s = '';
if (!$scriptAlreadyOut){
$s .= $this->getscriptOutput();
$scriptAlreadyOut = true;
}
if ($this->totalLists <= 0) return '';
if (($this->options['auto_display'] & PAGE_AUTO_GOTO) != 0){
if ($this->totalList == 1) return '';
}
$p = $this->currentPage + 1;
if ($p > $this->totalPages) $p = 1;
$url_pattern = sprintf($this->options['href_pattern'], '@');
$s .= sprintf($this->resource['goto'], $p, $this->totalPages, $url_pattern, $this->options['seach_regex']);
return $s;
}
// }}} END Protected get***Output Methods
// protected method
function outputAll(){
$opt_auto = $this->options['auto_display'];
if ($this->totalRecords == 0)
return false;
if ($this->totalPages == 1 && ($opt_auto & PAGE_AUTO_PAGE) != 0)
return true;
echo '<form method="GET" onsubmit="return false;">';
echo $this->getInfoOutput().' <br>';
echo $this->getFirstOutput($opt_auto).' ';
echo $this->getPreviousOutput($opt_auto).' ';
echo $this->getBackwardOutput($opt_auto).' ';
echo $this->getListOutput().' ';
echo $this->getForwardOutput($opt_auto).' ';
echo $this->getNextOutput($opt_auto).' ';
echo $this->getLastOutput($opt_auto).' <br>';
echo $this->getGotoOutput().' ';
echo '</form>';
}
}
// ----------------------------------------------------------------------------
class PageDefaultNavigator extends PageCustomizedNavigator
{
function PageDefaultNavigator(){
$this->__construct();
}
function __construct(){
$this->resource = array(
'info' => 'Total %1$d record(s), %2$d page(s), %3$d records per page',
'goto' => 'Go to page <input name="txtGotoPage" type="text" size="4" value="%1$d"> of %2$d, <input name="btnGotoPage" type="button" value="GO" onclick="gotoPage(this.form, %1$d, %2$d, '%3$s', '%4$s');">',
'first' => '[First]',
'prev' => '[Previous %2$d page(s)]',
'backward' => '[Backward]',
'page' => '[%1$d]',
'current_page' => '<b>[%1$d]</b>',
'forward' => '[Forward]',
'next' => '[Next %2$d page(s)]',
'last' => '[Last]'
);
$this->options = array(
'records_per_page' => 10,
'pages_per_list' => 10,
'list_seperator' => ',',
'href_pattern' => '?p=%1$s',
'seach_regex' => 'p=',
'anchor_extra' => '',
'auto_display' => PAGE_AUTO_NONE
);
$this->err_msg = array(
1 => 'Invalid page number!',
2 => 'Exceed max page number!'
);
}
}
?>
[/code:1:204da7b438]
longnetpro 回复于:2004-05-16 11:12:40 test.php
[code:1:10fc4e26c2]
<?php
define('_IN_APP', 1);
if (!defined('_IN_APP')) exit;
?>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>分页类测试代码</title>
</head>
<body>
<?php
require_once ('pagenavigator.class.php');
$currentPage = $_GET['p'];
if ($currentPage == '' || !is_numeric($currentPage))
$currentPage = 1;
class MyPageNav extends PageDefaultNavigator
{
function MyPageNav(){
$this->__construct();
}
function __construct(){
parent::__construct();
$this->resource = array(
'info' => '共%1$d条记录,%2$d页, 每页%3$d条记录',
'goto' => '共%2$d页,前往第 <input name="txtGotoPage" type="text" size="4" value="%1$d"> 页 <input name="btnGotoPage" type="button" value="GO" onclick="gotoPage(this.form, %1$d, %2$d, '%3$s', '%4$s');">',
'first' => '[首页]',
'prev' => '[前翻%2$d页]',
'backward' => '[上一页]',
'page' => '[%1$d]',
'current_page' => '<b>[%1$d]</b>',
'forward' => '[下一页]',
'next' => '[后翻%2$d页]',
'last' => '[末页]'
);
$this->options = array(
'records_per_page' => 15,
'pages_per_list' => 7,
'list_seperator' => ' ',
'href_pattern' => '?pp=1&p=%1$s',
'seach_regex' => 'p=',
'anchor_extra' => '',
'auto_display' => PAGE_AUTO_LIST_ALL
);
$this->err_msg = array(
1 => '无效的页码!',
2 => '超过了最大页码数!'
);
}
}
$totalRecords = 583;
$mypagenav = new MyPageNav;
$mypagenav->setTotalRecords($totalRecords);
$mypagenav->prepare();
$mypagenav->calculate($currentPage);
$mypagenav->outputAll();
for($i = 0;$i < $mypagenav->recordsInPage; $i++){
echo 'Record: '.($mypagenav->recordOffset + $i + 1)."<br>n";
}
$mypagenav->setOption('auto_display', PAGE_AUTO_PREV_NEXT);
$mypagenav->outputAll();
?>
</body>
</html>
[/code:1:10fc4e26c2]
numlock 回复于:2004-05-16 13:59:52 :shock: 好复杂呀!
我有一个分页类和一个分页函数。功能一样,不过函数用起来要简单,而且速度也稍快些!所以我用的还是函数!
longnetpro 回复于:2004-05-16 14:12:42 楼上说得对!
我原来也是用函数的,大概写起来也不会超过三十行。但扩展性与通用性都不强,也没有有效性检查,要重新换个形式都很麻烦,而且也不灵活,这才会想到用类的,基本上解决原来所有的问题。复杂一点也没有办法,有得就有失嘛。不过用起来不麻烦,速度肯定要比用函数慢很多。我发现只要用到类,肯定比用函数复杂好多倍,代码也长好多倍,但实在是没有办法啊。
numlock 回复于:2004-05-16 15:31:33 [quote:8a737bb9a4]有得就有失[/quote:8a737bb9a4]
:D 同意!
vidarz 回复于:2004-05-16 18:04:09 收藏先,外加支持。
poacher 回复于:2004-05-17 00:05:03 到 PHPE.net 下载 Show_page 类吧,功能十分好用
vidarz 回复于:2004-05-17 01:02:56 [quote:13bd59fec4="poacher"]到 PHPE.net 下载 Show_page 类吧,功能十分好用[/quote:13bd59fec4]
PHPE有高手,但未必比这里的高手厉害,你是新人吧?
yoursmile 回复于:2004-05-18 19:12:08 收藏了。
哈哈。
camel2004 回复于:2004-05-19 15:01:05 老大我试了试出现以下提示
Fatal error: Failed opening required 'pagenavigator.class.php' (innclude_path='.:/usr/share/pear')
为何??
longnetpro 回复于:2004-05-19 19:55:45 应该是把两个文件放到同一个目录下面后就没有问题。从提示上好象是说文件打开失败,是不是你设置了什么别的选项?我在WINDOWS下没有出现问题。对UNIX我不太熟,请其它高手解答。对了,两个文件的文件名别弄错了。如果还不行,把test.php中的require_once那一句改成require_onec('./pagenavigator.class.php');应该就没有问题了,如果还不行,我也不知道为什么了。
算了,可能是CU转换代码后有些问题,我自己试了一下,发现COPY成文件后也出错了。
已经重新发布,请访问:
http://longnetpro.xicp.net/demo
camel2004 回复于:2004-05-20 08:25:04 楼主我是用的linux9.0在同一目录下,用require_onec('./pagenavigator.class.php');也试过了还是不行.
longnetpro 回复于:2004-05-20 10:19:41 sorry,是require_once不是require_onec。你的PHP版本是多少?要不你把文件名改一下。没道理呀,如果是逻辑错误还有可能,出现failed to opening required "...",实在是说不通,是不是你的服务器或是PHP.INI中的设置有问题?要么文件名中不能有两个点?或是LINUX有特殊设置?请哪位精通LINUX的高手说一下吧。
你重新下载源代码了吗?如果没有,就下载后再试试看。
camel2004 回复于:2004-05-20 11:55:28 行了,谢谢老大,速度满快的,我已经用上去了,比其他的分页好使!!
不过显示部分最好放在另外一个文件中就更好了,不知老大同意否?
longnetpro 回复于:2004-05-20 12:23:00 [quote:13e895651a="camel2004"]行了,谢谢老大,速度满快的,我已经用上去了,比其他的分页好使!!
不过显示部分最好放在另外一个文件中就更好了,不知老大同意否?[/quote:13e895651a]
那你自己看着办了,我那个demo只是说明用法。类已经封装好了,怎么用是你自己的事。
epaulin 回复于:2004-06-11 12:38:45 用了一下,非常棒,谢谢 longnetpro。
发现了一个小问题,当总记录数刚好为每页显示记录数整数倍时最后一页记录无法正常显示,这个时候 $mypagenav->recordsInPage 为 0 。
对应在程序的第 61 行:
[code:1:7a4a071dd1]
$rip = ($cp == $tp)? ($tr % $rpp) : $rpp;
换为下面的正常了:
$rip = ($cp == $tp)? (($tr % $rpp)==0?$rpp:($tr % $rpp)) : $rpp;
[/code:1:7a4a071dd1]
longnetpro 回复于:2004-06-11 14:50:37 的确是我疏忽了,看来测试还不够完全。谢谢epaulin的提醒。幸好涉及改动比较小。
但epaulin改的也不完全,因为没有考虑到$tr(总记录数)为零的情况,另外列表也有同样的问题。
因此改动如下:
找到第40行类PageNavigator的calculate方法,将此方法的整个代码选中,用以下代码替换(中间作了一些修正):
[code:1:f41d50ba0d]
function calculate($currentPage = 1, $totalRecords = -1){
if ($totalRecords >= 0)
$this->totalRecords = intval($totalRecords);
if ($this->totalRecords <= 0)
return false;
$tr = $this->totalRecords;
$rpp = $this->recordsPerPage;
$ppl = $this->pagesPerList;
$tp = intval(ceil($tr / $rpp));
$tl = intval(ceil($tp / $ppl));
$cp = ($currentPage > 0 || $currentPage == -1)? $currentPage : 1;
$cp = ($cp == -1 || $cp > $tp)? $tp : $cp;
$cl = intval(ceil($cp / $ppl));
$ro = ($cp - 1) * $rpp;
$po = ($cl - 1) * $ppl;
$rip = $tr % $rpp;
$rip = ($tr == 0 || $cp == $tp && $rip != 0)? $rip : $rpp;
$pil = $tp % $ppl;
$pil = ($tp == 0 || $cl == $tl && $pil != 0)? $pil : $ppl;
$this->previousPages = ($cl <= 1)? 0 : $ppl;
if ($cl == $tl){
$this->nextPages = 0;
}else if ($cl >= 1 && $cl == $tl - 1){
$this->nextPages = $tp % $ppl;
if ($this->nextPages == 0)
$this->nextPages = $ppl;
}else{
$this->nextPages = $ppl;
}
$this->currentPage = $cp;
$this->currentList = $cl;
$this->totalPages = $tp;
$this->totalLists = $tl;
$this->recordOffset = $ro;
$this->pageOffset = $po;
$this->recordsInPage = $rip;
$this->pagesInList = $pil;
return true;
}
[/code:1:f41d50ba0d]
这样就行了。
另外,文件已重新上传,演示也改写。
URL: http://www.longnetpro.com/demo
再次感谢epaulin指出其中的bug。
lip199162 回复于:2004-12-17 11:06:30 这么好的分页程序,可是小弟也下载了一个玩玩,感觉很好,只是有一事不明,还望兄弟指点:我不知道怎样加上自己的url参数,请大哥赐教。万分感谢!
php爱好者站 http://www.phpfans.net 为phper提供一切资讯.
请访问:
http://www.longnetpro.com/demo
http://longnetpro.xicp.net/demo
[/b:d3677449b5][/size:d3677449b5]
看到大家都搞分页类,弄得心痒痒的,就忍不住把我半年前写的一个分页类修改了一下,也抛出来了。
说明:
这是个包,内含几个分页类,是半年前写的,今天做了一些修正。这次在核心代码不变的情况下,主要对扩展性与易用性上面做了改进。
这个包是按照OO的思想,按逻辑层次设计的,共有三层继承。基类为PageNavigator,其子类为PageCustomizedNavigator,下一级子类为PageDefaultNavigator,再下级子类就由用户根据需求自定义了。
继承了我一贯的OO作风,一个类要充分发挥它的作用,不相关的内容坚决不放在一个类中,业务逻辑与显示逻辑严格分离,永远要考虑类的封装性(接口的友好性)与可持续发展能力(类可扩展能力),这个包中的类基本遵循以上原则。这些类不但提供给程序员友好的扩展接口,使之功能更多更强,也可以直接使用它的默认形式。你将会在我给的例子中看到,如何将默认的英文输出用简单的资源重定义即变为全中文输出,你甚至可以在不改变任何核心代码的情况下改变输出文字——只简单重载一下构造函数或是用set***方法从外部设置——显示文字绝不会出现在核心代码之中。此类对输入进行严格检查,自动容错,自动检测输入有效性,保证分页都在有效的范围之内。有多个自动显示选项,可以设置是否根据情况显示上页下页等或是强制显示。特别加了一个“跳到第x页”的FORM,可手工输入页号进行跳转,并用JS进行有效性检测。
显示内容:
分三大部分,一是信息部分,二是列表部分,三是跳转部分。下面简单说一下三个部分。
信息部分:显示共有几条记录,共多少页,每页几条记录。
列表部分:即为带URL的页码号,它又分为“首页”、“前*页”、“上一页”、连续的页码、“下一页”、“后*页”、“末页”这七个部分,每一个部分在类中都有一个方法得到这个部分的字符串表达,每个这类方法都是protected的,如果需要可被子类重载——如果你需要定制自己的显示方式,可重载它们,在一般情况下,默认的方式通过设置不同的参数已足够用了(不需要你对代码做任何修改,只需设置参数即可)。
跳转部分:这个部分是个FORM,可以输入页码直接跳转,用JS代码作有效性检测并跳转到相应的页面。
三个类的简要介绍:
PageNavigator:基类,纯计算类,只需输入总记录数与当前页号,则根据参数算出其它所有必要数据(包括记录的偏移量,这个值可以用在MYSQL中的LIMIT中,还有其它一些数据)。
PageCustomizedNavigator:PageNavigator的子类,根据计算出来的数据及以有参数与资源变量生成上面所述三个部分的字符串表达,其中列表部分会带URL。这个类中所有的get***Output方法都是protected,可以被其子类重载,以便定制你自己的表示方式。最后一个outputAll方法是输出默认形式的列表。
PageDefaultNavigator:这个类在PageCustomizedNavigator上继承。它没有具体的操作方法,只是重载了一下父类的构造函数,装载了一个英文资源与一些默认的参数,如果调用这个类的outputAll方法就会按默认方式输出列表信息。
最后是关于测试文件的说明:
这个测试意在说明如何定制列表的输出形式。可以看到,仅通过重载PageDefaultNavigator类或是PageCustomizedNavigator类的构造函数,将英文对应的翻译成中文,在不用修改任何核心代码的情况下,就将整个列表用中文显示出来。同时,代码的调用也极为简单,无非就是几步:创建对象,设置总记录数,调用prepare方法进行准备,调用calculate方法计算出所有数据,然后设置显示参数(或直接用默认值,可选),最后就是输出了。如果你自己做好了一个类,可以把它单独放到一个文件中,并在这个类中加入一个方法使以上的前几个步骤合在这个方法中(比如加一个initialize方法),以达到更好的封装,使调用更为简洁,接口更为清晰。当然,仅用重载构造函数或是用setResource或是setOptions方法使用外部资源只是定制输出列表的一个最基本方法,更高级的是重载一些保护的(protected)方法。由于每个方法的功能非常单一,你完全不用担心对些方法的任何修改会影响到其它的功能——除非你自己人为的在一个方法中去做与它本身毫无关系的事。如果你不想输出所有的信息,你可以在从基类派生出来的你自己的类中加入一个输出方法以取代outputAll方法,或是干脆重载它,反正输出的各个部分都是现成的,你的输出方法只不过是取你要用的那些部分罢了。如果你愿意,不妨自己加几个参数进行控制。
文件:
本来这几个文件是我的库中的几个文件,与其它类库或是函数库有关联,单独拿出来是运行不了的。今天作了一下修改,可以独立运行了。
文件只有两个,一个是包所在的文件pagenavigator.class.php,这次有些简短的英文注释,希望我的英语不是太滥,大家还能看得懂——不过我想从程序上来说应该还是比较易懂的。第二个还是老规矩,test.php,测试文件,放在一个目录下,可以运行。当然,没有详细debug,可能会有一些问题,不过用OO编程,维护起来的确容易多了,写程序中还好没有碰到太多逻辑的BUG。
另外,我原来一直强调,分页类就是分页类,不应当与数据库搞在一起,因此我这个包中的类没有一个是与数据库有关的,连一个SQL语句都没有——我个人认为,如果在分页类里放与数据库有关的内容,只能说明写程序的人对OO还没有理解清楚。但是不是这个包就不能与数据库结合用呢?肯定不是。其实在TEST中,就可以把for循环改成数据库循环即可。理论上说分页类与数据库没有什么过多直接的关系,因为分页类中唯一需要知道的外部数据就是总记录数,与数据库有关的代码只负责把数据库中所需要显示的数据取出显示就行了,这个过程与分页类是没有任何关系的(除了在查询前需要从分页类得到LIMIT的两上参数外)。
具体的内容还是看一下代码吧。
最后说一句:这个说明是直接打出来的,没有打草稿,因此可能会出现语句不通或是语法错误或是打字错误等等,就请大家包涵一下了。后面分两帖帖上类代码与测试代码。
longnetpro 回复于:2004-05-16 11:12:04 pagenavigator.class.php
[code:1:204da7b438]
<?php
if(!defined('_IN_APP')) exit;
define('PAGE_RPP_DEF', 10);
define('PAGE_PPL_DEF', 10);
class PageNavigator
{
var $recordsPerPage = PAGE_RPP_DEF; // how many records per page, default 10
var $pagesPerList = PAGE_PPL_DEF; // how many pages per list, default 10
var $totalRecords = 0; // number of all records
var $currentPage = 1; // current page number. 1 based(first number is 1)
var $currentList = 1; // current list number. 1 based
var $totalPages = 0; // number of all pages.
var $totalLists = 0; // number of all lists.
var $recordOffset = 0; // offset of the first record in the current page. 0 based
var $pageOffset = 0; // offset of the first page in the current list. 0 based
var $recordsInPage = 0; // number of records in current page.
var $pagesInList = 0; // number of pages in current list.
var $previousPages = 0; // number of the previous pages in the list
var $nextPages = 0; // number of the next pages in the list
function setParameter($recordsPerPage = 10, $pagesPerList = 10){
$this->recordsPerPage = intval($recordsPerPage);
$this->pagesPerList = intval($pagesPerList);
}
function setTotalRecords($totalRecords){
$this->totalRecords = intval($totalRecords);
}
// $currentPage: current page number, if the value is -1 means the last page
// $totalRecords: number of all records, if the value is -1 means using the
// stored one.
function calculate($currentPage = 1, $totalRecords = -1){
if ($totalRecords >= 0)
$this->totalRecords = intval($totalRecords);
if ($this->totalRecords <= 0)
return false;
$tr = $this->totalRecords;
$rpp = $this->recordsPerPage;
$ppl = $this->pagesPerList;
$tp = intval(ceil($tr / $rpp));
$tl = intval(ceil($tp / $ppl));
$cp = ($currentPage > 0 || $currentPage == -1)? $currentPage : 1;
$cp = ($cp == -1 || $cp > $tp)? $tp : $cp;
$cl = intval(ceil($cp / $ppl));
$ro = ($cp - 1) * $rpp;
$po = ($cl - 1) * $ppl;
$rip = ($cp == $tp)? ($tr % $rpp) : $rpp;
$pil = ($cl == $tl)? ($tp % $ppl) : $ppl;
$this->previousPages = ($cl <= 1)? 0 : $ppl;
if ($cl == $tl){
$this->nextPages = 0;
}else if ($cl >=1 && $cl == $tl - 1){
$this->nextPages = $tp % $ppl;
}else{
$this->nextPages = $ppl;
}
$this->currentPage = $cp;
$this->currentList = $cl;
$this->totalPages = $tp;
$this->totalLists = $tl;
$this->recordOffset = $ro;
$this->pageOffset = $po;
$this->recordsInPage = $rip;
$this->pagesInList = $pil;
return true;
}
}
// ----------------------------------------------------------------------------
define('PAGE_AUTO_NONE', 0);
define('PAGE_AUTO_FIRST_LAST', 1);
define('PAGE_AUTO_PREV_NEXT', 2);
define('PAGE_AUTO_FORWARD_BACKWARD', 4);
define('PAGE_AUTO_PAGE', 8);
define('PAGE_AUTO_GOTO', 16);
define('PAGE_AUTO_LIST_ALL', PAGE_AUTO_FIRST_LAST + PAGE_AUTO_PREV_NEXT +
PAGE_AUTO_FORWARD_BACKWARD + PAGE_AUTO_PAGE);
define('PAGE_AUTO_ALL', PAGE_AUTO_LIST_ALL + PAGE_AUTO_GOTO);
class PageCustomizedNavigator extends PageNavigator
{
var $resource = null;
var $options = null;
function PageCustomizedNavigator(){
$this->__construct();
}
function __construct(){
$this->resource = array();
$this->options = array();
}
function setResource($resource){
$this->resource =& $resource;
}
function setOptions($options){
if (!is_array($options)) return;
$this->options = $options;
}
function setOption($option, $value){
$this->options[$option] = $value;
}
function setAutoDisplay($option = PAGE_AUTO_LIST_ALL, $disabled = false){
if (!isset($this->options['auto_display']))
return;
if ($disabled){
$this->options['auto_display'] &= ~$option;
}else{
$this->options['auto_display'] |= $option;
}
}
// public
function prepare(){
$rpp = 0;
if (isset($this->options['records_per_page'])){
$rpp = intval($this->options['records_per_page']);
}
if ($rpp == 0) $rpp = PAGE_RPP_DEF;
$ppl = 0;
if (isset($this->options['pages_per_list'])){
$ppl = intval($this->options['pages_per_list']);
}
if ($ppl == 0) $ppl = PAGE_PPL_DEF;
$this->setParameter($rpp, $ppl);
}
// private
function _validate_page_number($page_number){
$pn = intval($page_number);
if ($pn < 1) $pn = 1;
if ($pn > $this->totalPages) $pn = $this->totalPages;
return $pn;
}
// private
function _validate_list_number($list_number){
$ln = intval($list_number);
if ($ln < 1) $ln = 1;
if ($ln > $this->totalLists) $ln = $this->totalLists;
return $ln;
}
// protected method, may be overriden by subclasses
function updateHref($page_number = 1){
$page_number = $this->_validate_page_number($page_number);
$href = sprintf($this->options['href_pattern'], $page_number);
return $href;
}
// protected method, may be overriden by subclasses
function getLink($page_number, $text){
$href = $this->updateHref($page_number);
$extra = $this->options['anchor_extra'];
if ($extra != '') $extra = ' '.$extra;
$link = '<a href="'.$href.'"'.$extra.'>'.$text.'</a>';
return $link;
}
// protected method, may be overriden by subclasses
function makeLink(&$text, $page_number, $list_number = -1){
if ($page_number == $this->currentPage) return false;
if ($list_number > 0 && $list_number == $this->currentList) return false;
$text = $this->getLink($page_number, $text);
return true;
}
// {{{ BEGIN Protected get***Output Methods
// protected method, may be overriden
// if not be overriden, using default processing
function getInfoOutput(){
$info = sprintf($this->resource['info'],
$this->totalRecords, $this->totalPages, $this->recordsPerPage);
return $info;
}
function getFirstOutput($opt_auto){
$num = $this->_validate_page_number(1);
$first = sprintf($this->resource['first'], $num);
if ($this->makeLink($first, $num) || ($opt_auto & PAGE_AUTO_FIRST_LAST) == 0)
return $first;
return '';
}
function getLastOutput($opt_auto){
$num = $this->_validate_page_number($this->totalPages);
$last = sprintf($this->resource['last'], $num);
if ($this->makeLink($last, $num) || ($opt_auto & PAGE_AUTO_FIRST_LAST) == 0)
return $last;
return '';
}
function getPreviousOutput($opt_auto){
$num = $this->_validate_page_number($this->pageOffset);
$lnum = $this->_validate_list_number($this->currentList - 1);
$prev = sprintf($this->resource['prev'], $num, $this->previousPages);
if ($this->makeLink($prev, $num, $lnum) || ($opt_auto & PAGE_AUTO_PREV_NEXT) == 0)
return $prev;
return '';
}
function getNextOutput($opt_auto){
$num = $this->_validate_page_number($this->pageOffset + $this->pagesInList + 1);
$lnum = $this->_validate_list_number($this->currentList + 1);
$next = sprintf($this->resource['next'], $num, $this->nextPages);
if ($this->makeLink($next, $num, $lnum) || ($opt_auto & PAGE_AUTO_PREV_NEXT) == 0)
return $next;
return '';
}
function getBackwardOutput($opt_auto){
$num = $this->_validate_page_number($this->currentPage - 1);
$backward = sprintf($this->resource['backward'], $num);
if ($this->makeLink($backward, $num) || ($opt_auto & PAGE_AUTO_FORWARD_BACKWARD) == 0)
return $backward;
return '';
}
function getForwardOutput($opt_auto){
$num = $this->_validate_page_number($this->currentPage + 1);
$forward = sprintf($this->resource['forward'], $num);
if ($this->makeLink($forward, $num) || ($opt_auto & PAGE_AUTO_FORWARD_BACKWARD) == 0)
return $forward;
return '';
}
function getListOutput(){
$p_sep = $this->options['list_seperator'];
$page = '';
for ($i = $this->pageOffset + 1, $j = 0; $j < $this->pagesInList; $i++, $j++){
$link = sprintf($this->resource['page'], $i);
if (!$this->makeLink($link, $i))
$link = sprintf($this->resource['current_page'], $i);
$page .= $link.$p_sep;
}
if ($p_sep != '') $page = substr($page, 0, - strlen($p_sep));
return $page;
}
function _filter_error_message($message = ''){
$tr = array("rn" => "n", "r" => "n");
$message = strtr($message, $tr);
$message = str_replace("n", 'n', $message);
return $message;
}
function getscriptOutput(){
$err1 = $this->_filter_error_message($this->err_msg[1]);
$err2 = $this->_filter_error_message($this->err_msg[2]);
$script = <<< EOF
<script language="Javascript" type="text/Javascript">
<!--
var errmsg = new Array();
errmsg[1] = '$err1';
errmsg[2] = '$err2';
function gotoPage(theform, currentpage, maxpages, urlpattern, se){
var i = theform.txtGotoPage.value;
var errno = 0;
if (i.search(/^[0-9]+$/) == -1){
errno = 1;
} else {
i = parseInt(i);
if (i > maxpages){
errno = 2;
} else {
var regex = '/(b'+se+')'+'@(&|$)/';
eval('var se0 = ' + regex + ';');
var s = urlpattern.replace(se0, '$1'+i+'$2');
self.location.href = s;
return;
}
}
if (errno != 0){
window.alert(errmsg[errno]);
theform.txtGotoPage.value = currentpage;
theform.txtGotoPage.focus();
}
}
// -->
</script>
EOF;
return $script;
}
function getGotoOutput(){
static $scriptAlreadyOut = false;
$s = '';
if (!$scriptAlreadyOut){
$s .= $this->getscriptOutput();
$scriptAlreadyOut = true;
}
if ($this->totalLists <= 0) return '';
if (($this->options['auto_display'] & PAGE_AUTO_GOTO) != 0){
if ($this->totalList == 1) return '';
}
$p = $this->currentPage + 1;
if ($p > $this->totalPages) $p = 1;
$url_pattern = sprintf($this->options['href_pattern'], '@');
$s .= sprintf($this->resource['goto'], $p, $this->totalPages, $url_pattern, $this->options['seach_regex']);
return $s;
}
// }}} END Protected get***Output Methods
// protected method
function outputAll(){
$opt_auto = $this->options['auto_display'];
if ($this->totalRecords == 0)
return false;
if ($this->totalPages == 1 && ($opt_auto & PAGE_AUTO_PAGE) != 0)
return true;
echo '<form method="GET" onsubmit="return false;">';
echo $this->getInfoOutput().' <br>';
echo $this->getFirstOutput($opt_auto).' ';
echo $this->getPreviousOutput($opt_auto).' ';
echo $this->getBackwardOutput($opt_auto).' ';
echo $this->getListOutput().' ';
echo $this->getForwardOutput($opt_auto).' ';
echo $this->getNextOutput($opt_auto).' ';
echo $this->getLastOutput($opt_auto).' <br>';
echo $this->getGotoOutput().' ';
echo '</form>';
}
}
// ----------------------------------------------------------------------------
class PageDefaultNavigator extends PageCustomizedNavigator
{
function PageDefaultNavigator(){
$this->__construct();
}
function __construct(){
$this->resource = array(
'info' => 'Total %1$d record(s), %2$d page(s), %3$d records per page',
'goto' => 'Go to page <input name="txtGotoPage" type="text" size="4" value="%1$d"> of %2$d, <input name="btnGotoPage" type="button" value="GO" onclick="gotoPage(this.form, %1$d, %2$d, '%3$s', '%4$s');">',
'first' => '[First]',
'prev' => '[Previous %2$d page(s)]',
'backward' => '[Backward]',
'page' => '[%1$d]',
'current_page' => '<b>[%1$d]</b>',
'forward' => '[Forward]',
'next' => '[Next %2$d page(s)]',
'last' => '[Last]'
);
$this->options = array(
'records_per_page' => 10,
'pages_per_list' => 10,
'list_seperator' => ',',
'href_pattern' => '?p=%1$s',
'seach_regex' => 'p=',
'anchor_extra' => '',
'auto_display' => PAGE_AUTO_NONE
);
$this->err_msg = array(
1 => 'Invalid page number!',
2 => 'Exceed max page number!'
);
}
}
?>
[/code:1:204da7b438]
longnetpro 回复于:2004-05-16 11:12:40 test.php
[code:1:10fc4e26c2]
<?php
define('_IN_APP', 1);
if (!defined('_IN_APP')) exit;
?>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>分页类测试代码</title>
</head>
<body>
<?php
require_once ('pagenavigator.class.php');
$currentPage = $_GET['p'];
if ($currentPage == '' || !is_numeric($currentPage))
$currentPage = 1;
class MyPageNav extends PageDefaultNavigator
{
function MyPageNav(){
$this->__construct();
}
function __construct(){
parent::__construct();
$this->resource = array(
'info' => '共%1$d条记录,%2$d页, 每页%3$d条记录',
'goto' => '共%2$d页,前往第 <input name="txtGotoPage" type="text" size="4" value="%1$d"> 页 <input name="btnGotoPage" type="button" value="GO" onclick="gotoPage(this.form, %1$d, %2$d, '%3$s', '%4$s');">',
'first' => '[首页]',
'prev' => '[前翻%2$d页]',
'backward' => '[上一页]',
'page' => '[%1$d]',
'current_page' => '<b>[%1$d]</b>',
'forward' => '[下一页]',
'next' => '[后翻%2$d页]',
'last' => '[末页]'
);
$this->options = array(
'records_per_page' => 15,
'pages_per_list' => 7,
'list_seperator' => ' ',
'href_pattern' => '?pp=1&p=%1$s',
'seach_regex' => 'p=',
'anchor_extra' => '',
'auto_display' => PAGE_AUTO_LIST_ALL
);
$this->err_msg = array(
1 => '无效的页码!',
2 => '超过了最大页码数!'
);
}
}
$totalRecords = 583;
$mypagenav = new MyPageNav;
$mypagenav->setTotalRecords($totalRecords);
$mypagenav->prepare();
$mypagenav->calculate($currentPage);
$mypagenav->outputAll();
for($i = 0;$i < $mypagenav->recordsInPage; $i++){
echo 'Record: '.($mypagenav->recordOffset + $i + 1)."<br>n";
}
$mypagenav->setOption('auto_display', PAGE_AUTO_PREV_NEXT);
$mypagenav->outputAll();
?>
</body>
</html>
[/code:1:10fc4e26c2]
numlock 回复于:2004-05-16 13:59:52 :shock: 好复杂呀!
我有一个分页类和一个分页函数。功能一样,不过函数用起来要简单,而且速度也稍快些!所以我用的还是函数!
longnetpro 回复于:2004-05-16 14:12:42 楼上说得对!
我原来也是用函数的,大概写起来也不会超过三十行。但扩展性与通用性都不强,也没有有效性检查,要重新换个形式都很麻烦,而且也不灵活,这才会想到用类的,基本上解决原来所有的问题。复杂一点也没有办法,有得就有失嘛。不过用起来不麻烦,速度肯定要比用函数慢很多。我发现只要用到类,肯定比用函数复杂好多倍,代码也长好多倍,但实在是没有办法啊。
numlock 回复于:2004-05-16 15:31:33 [quote:8a737bb9a4]有得就有失[/quote:8a737bb9a4]
:D 同意!
vidarz 回复于:2004-05-16 18:04:09 收藏先,外加支持。
poacher 回复于:2004-05-17 00:05:03 到 PHPE.net 下载 Show_page 类吧,功能十分好用
vidarz 回复于:2004-05-17 01:02:56 [quote:13bd59fec4="poacher"]到 PHPE.net 下载 Show_page 类吧,功能十分好用[/quote:13bd59fec4]
PHPE有高手,但未必比这里的高手厉害,你是新人吧?
yoursmile 回复于:2004-05-18 19:12:08 收藏了。
哈哈。
camel2004 回复于:2004-05-19 15:01:05 老大我试了试出现以下提示
Fatal error: Failed opening required 'pagenavigator.class.php' (innclude_path='.:/usr/share/pear')
为何??
longnetpro 回复于:2004-05-19 19:55:45 应该是把两个文件放到同一个目录下面后就没有问题。从提示上好象是说文件打开失败,是不是你设置了什么别的选项?我在WINDOWS下没有出现问题。对UNIX我不太熟,请其它高手解答。对了,两个文件的文件名别弄错了。如果还不行,把test.php中的require_once那一句改成require_onec('./pagenavigator.class.php');应该就没有问题了,如果还不行,我也不知道为什么了。
算了,可能是CU转换代码后有些问题,我自己试了一下,发现COPY成文件后也出错了。
已经重新发布,请访问:
http://longnetpro.xicp.net/demo
camel2004 回复于:2004-05-20 08:25:04 楼主我是用的linux9.0在同一目录下,用require_onec('./pagenavigator.class.php');也试过了还是不行.
longnetpro 回复于:2004-05-20 10:19:41 sorry,是require_once不是require_onec。你的PHP版本是多少?要不你把文件名改一下。没道理呀,如果是逻辑错误还有可能,出现failed to opening required "...",实在是说不通,是不是你的服务器或是PHP.INI中的设置有问题?要么文件名中不能有两个点?或是LINUX有特殊设置?请哪位精通LINUX的高手说一下吧。
你重新下载源代码了吗?如果没有,就下载后再试试看。
camel2004 回复于:2004-05-20 11:55:28 行了,谢谢老大,速度满快的,我已经用上去了,比其他的分页好使!!
不过显示部分最好放在另外一个文件中就更好了,不知老大同意否?
longnetpro 回复于:2004-05-20 12:23:00 [quote:13e895651a="camel2004"]行了,谢谢老大,速度满快的,我已经用上去了,比其他的分页好使!!
不过显示部分最好放在另外一个文件中就更好了,不知老大同意否?[/quote:13e895651a]
那你自己看着办了,我那个demo只是说明用法。类已经封装好了,怎么用是你自己的事。
epaulin 回复于:2004-06-11 12:38:45 用了一下,非常棒,谢谢 longnetpro。
发现了一个小问题,当总记录数刚好为每页显示记录数整数倍时最后一页记录无法正常显示,这个时候 $mypagenav->recordsInPage 为 0 。
对应在程序的第 61 行:
[code:1:7a4a071dd1]
$rip = ($cp == $tp)? ($tr % $rpp) : $rpp;
换为下面的正常了:
$rip = ($cp == $tp)? (($tr % $rpp)==0?$rpp:($tr % $rpp)) : $rpp;
[/code:1:7a4a071dd1]
longnetpro 回复于:2004-06-11 14:50:37 的确是我疏忽了,看来测试还不够完全。谢谢epaulin的提醒。幸好涉及改动比较小。
但epaulin改的也不完全,因为没有考虑到$tr(总记录数)为零的情况,另外列表也有同样的问题。
因此改动如下:
找到第40行类PageNavigator的calculate方法,将此方法的整个代码选中,用以下代码替换(中间作了一些修正):
[code:1:f41d50ba0d]
function calculate($currentPage = 1, $totalRecords = -1){
if ($totalRecords >= 0)
$this->totalRecords = intval($totalRecords);
if ($this->totalRecords <= 0)
return false;
$tr = $this->totalRecords;
$rpp = $this->recordsPerPage;
$ppl = $this->pagesPerList;
$tp = intval(ceil($tr / $rpp));
$tl = intval(ceil($tp / $ppl));
$cp = ($currentPage > 0 || $currentPage == -1)? $currentPage : 1;
$cp = ($cp == -1 || $cp > $tp)? $tp : $cp;
$cl = intval(ceil($cp / $ppl));
$ro = ($cp - 1) * $rpp;
$po = ($cl - 1) * $ppl;
$rip = $tr % $rpp;
$rip = ($tr == 0 || $cp == $tp && $rip != 0)? $rip : $rpp;
$pil = $tp % $ppl;
$pil = ($tp == 0 || $cl == $tl && $pil != 0)? $pil : $ppl;
$this->previousPages = ($cl <= 1)? 0 : $ppl;
if ($cl == $tl){
$this->nextPages = 0;
}else if ($cl >= 1 && $cl == $tl - 1){
$this->nextPages = $tp % $ppl;
if ($this->nextPages == 0)
$this->nextPages = $ppl;
}else{
$this->nextPages = $ppl;
}
$this->currentPage = $cp;
$this->currentList = $cl;
$this->totalPages = $tp;
$this->totalLists = $tl;
$this->recordOffset = $ro;
$this->pageOffset = $po;
$this->recordsInPage = $rip;
$this->pagesInList = $pil;
return true;
}
[/code:1:f41d50ba0d]
这样就行了。
另外,文件已重新上传,演示也改写。
URL: http://www.longnetpro.com/demo
再次感谢epaulin指出其中的bug。
lip199162 回复于:2004-12-17 11:06:30 这么好的分页程序,可是小弟也下载了一个玩玩,感觉很好,只是有一事不明,还望兄弟指点:我不知道怎样加上自己的url参数,请大哥赐教。万分感谢!
php爱好者站 http://www.phpfans.net 为phper提供一切资讯.
相关阅读 更多 +