本来这篇文章是不想写的,要写早几年就应该写了,为甚么突然想起要写一篇这样的东西呢?无他,因为随着年岁的增长,近日发觉自己的记忆力下降得非常厉害,看过的东西转头即忘。莫非这是老年痴呆的先兆?因此赶紧记之,以作备忘。
开发系统时,FleaPHP的分页大家用得可能比较多了,但都是怎么用的呢?而且使用了多少种分页方法呢?哪种分页方法用的较多呢?日常使用过程中,对FleaPHP中的分页助手的原有功能是否满意呢?一直以来,本人对FleaPHP的分页助手的功能都不满意,灰常有意见。因为这个实在太简单了,简单到分页助手只是为你准备好分页数据,至于分页的显示样式等,则只能靠自己了。本人曾多次向dualface(廖宇雷)教主他老人家提出宝贵意见,但他老人家就是不接受,我有什么办法呢?!看到这里,有些看官自然有话要说,既然对分页助手诸多不满,为什么你自己不开发一个?这个嘛——,当然了,自己搞一个,也不是不行,但本人比较懒,平时只喜欢“拿来主义”,除非没有,逼得自己非去瞎搞不可,否则都是拿来即用。话又要说回来,如果样样都要自己搞一套,岂非老年痴呆得更快?何况已经有了一个分页自定义插件,我觉得大体上可以应付过去了,就不必再另搞一套了,无此必要。
孔老夫子因自己衰老得厉害,已经无法梦见周公了而常常哀叹。我呢,哎,人老了碎话就多,这更是要得老年痴呆的证据了,请看官原谅则个。
话确实多了,扯远了,回到正题。继续谈分页......
本人在进行分页时,下面三种分页样式经常用到,就是:
1、使用分页自定义控件,就是Pagernav插件,显示“<<上页 1 2 3 ...... 下页>>”链接字串;图示效果:
2、直接使用分页助手,显示分页索引数字链接字串,如:“1 2 3 4 ...... 8”;图示效果:
3、对分页助手进行功能扩展,显示“首页|上页|下页|末页”链接字串;图示效果:
是否还有其它分页方法?比如Ajax分页。这个当然可以有,而且是真的有。但由于与本文所述无关,因此忽略不讲。
以上三种分页都需要用到分页助手,因此,我们先复习一下分页助手的构造函数原型。
/**
* 构造函数
*
* 如果 $source 参数是一个 TableDataGateway 对象,则 FLEA_Helper_Pager 会调用
* 该 TDG 对象的 findCount() 和 findAll() 来确定记录总数并返回记录集。
*
* 如果 $source 参数是一个字符串,则假定为 SQL 语句。这时,FLEA_Helper_Pager
* 不会自动调用计算各项分页参数。必须通过 setCount() 方法来设置作为分页计算
* 基础的记录总数。
*
* 同时,如果 $source 参数为一个字符串,则不需要 $conditions 和 $sortby 参数。
* 而且可以通过 setDBO() 方法设置要使用的数据库访问对象。否则 FLEA_Helper_Pager
* 将尝试获取一个默认的数据库访问对象。
*
* @param TableDataGateway|string $source
* @param int $currentPage
* @param int $pageSize
* @param mixed $conditions
* @param string $sortby
* @param int $basePageIndex
*
* @return FLEA_Helper_Pager
*/
function FLEA_Helper_Pager(& $source, $currentPage, $pageSize = 20, $conditions = null, $sortby = null, $basePageIndex = 0)
参数说明:
$source -- TableDataGateway 对象,也就是数据表对象实例;
$currentPage -- 当前页页码;
$pageSize -- 每页显示记录数,默认为每页显示20条记录;
$conditions -- 分页查询条件参数;
$sortby -- 记录排序参数,默认为null,即按ASC升序排列;
$basePageIndex -- 基本页索引参数,默认为0,即分页时以 0 开始计数,如果设为 1,即分页时以 1 开始计数;这个一直以来争议很大,为什么分页从 0 开始?教主没说。
复习完分页助手的构造函数原型后,继续讲自定义分页插件的使用。
1、分页自定义插件Pagernav的正确使用方法
第一步,下载Pagernav插件,并解压到相关目录下,我习惯放在public/WebControls目录下。
该插件只有两个文件:Pagernav.php 和pagenav.css 文件。
第二步,在配置文件中指定插件的存放目录。如下所示:
/**
* WebControls 扩展控件的保存目录
*/
'webControlsExtendsDir' => __PROJECT_ROOT__ . '/public/WebControls',
注意:__PROJECT_ROOT__为单入口文件中所定义的项目根目录,这是一个常量。
第三步,准备模板文件。代码如下面所示:
<link href="public/WebControls/pagenav.css" rel="stylesheet" type="text/css" />
......
<table width="100%" class="table">
<thead>
<tr>
<th width="2%" nowrap="nowrap">选择</th>
<th width="77%" nowrap="nowrap">标题</th>
<th width="11%" nowrap="nowrap">时间</th>
<th width="2%" nowrap="nowrap">状态</th>
<th width="8%" nowrap="nowrap">操作</th>
</tr>
</thead>
<tbody>
{{ section name=i loop=$lists }}
<tr>
<td><input type="checkbox" name="ids[]" id="ids[]" value="{{ $lists[i].art_id }}" /></td>
<td nowrap="nowrap">{{ $lists[i].title }}</td>
<td nowrap="nowrap">{{ $lists[i].created }}</td>
<td nowrap="nowrap">{{ $lists[i].status }}</td>
<td nowrap="nowrap"> <a href="{{ url controller='Article' action='Edit' id=$lists[i].art_id page=$page }}" title="编辑"><img src="images/24.png" width="16" height="16" align="absmiddle" /></a> <a href="{{ url controller='Article' action='Preview' id=$lists[i].art_id page=$page }}" title="预览" target="_blank"><img src="images/preview.png" width="16" height="16" align="absmiddle" /></a> <a href="{{ url controller='Article' action='Open' id=$lists[i].art_id page=$page }}" title="开放浏览"><img src="images/crm.gif" width="16" height="16" align="absmiddle" /></a> <a href="{{ url controller='Article' action='Delete' id=$lists[i].art_id page=$page }}" title="删除" οnclick="return confirm('确定要删除该记录吗?');"><img src="images/12.png" width="16" height="16" align="absmiddle" /></a> </td>
</tr>
{{ /section }}
</tbody>
</table>
<div class="cutpage">{{ webcontrol type="pagernav" name="pagenav" pager=$pagerData controller="Article" action="" }}</div>
......
上面的模板代码与分页相关的代码不多,需要注意的是:
page=$page -- 当前页码
{{ webcontrol type="pagernav" name="pagenav" pager=$pagerData controller="Article" action="" }} -- 构造分页链接字串
其中参数$pagerData为传入控件的分页参数。
如果要传递复杂的参数给自定义分页控件,如传入一个参数数组,可以将上面的代码修改为:
{{ webcontrol type="pagernav" name="pagenav" pager=$pagerData controller="Article" action="" __arrs=$arrs }}
如何构造自定义控件?由于超出本文范围,这里不做讲解。各位看官如有兴趣深入,可以看看下面这篇文章:
《使用 FleaPHP 的 WebControls 机制创建可复用的用户界面组件》(http://qeephp.com/bbs/viewthread.php?tid=1695&extra=page%3D1%26amp%3Bfilter%3Ddigest )
教主出品,必属精品,各位同学需要仔细揣摩。
第三步,编写后台PHP代码。代码如下面所示:
$page = (isset($_GET['page']) ? (int)$_GET['page'] : 0;
// 装载Pager助手类
FLEA::loadHelper('Pager');
// 获取Smarty实例句柄
$tpl = & $this->_getView();
$conditions = array(
array('uid', $this->user['UID'], '='),
);
$tblArt = & FLEA::getSingleton('Table_Articles');
$pager = & new FLEA_Helper_Pager($tblArt, $page, 15, $conditions, 'art_id DESC');
$rows = $pager->findAll();
$pagerData = $pager->getPagerData();
//dump($pagerData);
//exit;
$tpl->assign('lists', $rows);
$tpl->assign('pagerData', $pagerData);
$tpl->assign('page', $page);
$tpl->display('article_list.tpl');
同学们可以看看运行程序后,生成的分页数据样式:
dump($pagerData);
Array
(
[pageSize] => 2
[totalCount] => 6
[count] => 6
[pageCount] => 3
[firstPage] => 1
[firstPageNumber] => 1
[lastPage] => 3
[lastPageNumber] => 3
[prevPage] => 2
[prevPageNumber] => 2
[nextPage] => 3
[nextPageNumber] => 3
[currentPage] => 3
[currentPageNumber] => 3
[pagesNumber] => Array
(
[0] => 1
[1] => 2
[2] => 3
)
)
看到这里,同学们觉得分页是不是很简单?用教主的口头禅回答:“对,就是如此简单。”
需要说明的是,上面的讲解以FleaPHP 1.7.1524、Smarty基础。下面的讲解也一样。
Smarty的运行环境参数配置,请参看本人缪作:FleaPHP的单入口文件详解》(http://hegz.iteye.com/blog/646632 )
Pagernav分页插件还可以构造几种不同的分页连接串,我就不再深入了,大家回去自己研究。
同学们也可以看看教主的《Digg.com 样式的分页导航条》(http://qeephp.com/bbs/viewthread.php?tid=1299&extra=page%3D1%26amp%3Bfilter%3Ddigest )
讲解完Pagernav插件的使用后,接着讲解如何直接使用分页助手进行分页。
2、直接使用分页助手进行分页
讲解之前,大家先看一下《Pager类使用指南》(http://qeephp.com/bbs/viewthread.php?tid=657&highlight=%E6%8F%90%E4%BA%A4%E6%89%8B%E5%86%8C )这篇资料。
请注意其中的getNavbarIndexs()方法的使用,因为下面要用到。
当然了,这篇《指南》发表的较早,可能与FleaPHP 1.7.1524存在较大出入。但不要紧,我们只需要了解并掌握其分页方法即可。所谓“万变不离其宗”是也。
由于直接使用分页助手进行分页,方法就更加简单了。
第一步,准备分页模板。
与分页相关的代码如下面所示:
<a href="{{ url controller=$url.ctl action=$url.act page=$newsPager.firstPageNumber }}" title="首页">|<</a>
{{ section name=page loop=$newsNavbar }}
{{ if $newsNavbar[page].index == $newsPager.currentPage }}
<b><font color='red'>[{{ $newsNavbar[page].number }}]</font></b>
{{ else }}
<a href="{{ url controller=$url.ctl action=$url.act page=$newsNavbar[page].index }}">{{ $newsNavbar[page].number }}</a>
{{ /if }}
{{ /section }}
<a href="{{ url controller=$url.ctl action=$url.act page=$newsPager.lastPageNumber }}" title="末页">>|</a> 共有 <font color="Red">{{ $newsPager.count }}</font> 条记录,分为 <font color="Red">{{ $newsPager.pageCount }}</font> 页显示,每页 <font color="Red"> {{ $newsPager.pageSize }}</font> 条
模板代码似乎有点复杂。
第二步,编写后台PHP代码。代码如下面所示:
$page = (isset($_GET['page']) ? (int)$_GET['page'] : 1;
// 装载Pager助手类
FLEA::loadHelper('Pager');
// 获取Smarty实例句柄
$tpl = & $this->_getView();
$conditions = array(
array('uid', $this->user['UID'], '='),
);
$tblArt = & FLEA::getSingleton('Table_Articles');
$pager = & new FLEA_Helper_Pager($tblArt, $page, 15, $conditions, 'art_id DESC',1);
$rows = $pager->findAll();
$tpl->assign('lists', $rows);
$tpl->assign('page', $page);
// 构造分页数字字串
$tpl->assign('newsNavbar', $pager->getNavbarIndexs($page, 8));
// 构造分页状态
$tpl->assign('newsPager', $pager->getPagerData());
$tpl->assign('url', array('ctl' => 'Article','act' => null));
$tpl->display('article_list.tpl');
注意上面上面的代码:
$page = (isset($_GET['page']) ? (int)$_GET['page'] : 1;
$pager = & new FLEA_Helper_Pager($tblArt, $page, 15, $conditions, 'art_id DESC', 1);
已改变为页码由 1 开始算起。
这个比较简单,不再做展开,大家结合《Pager类使用指南》来理解就行。
下面最后讲一下如何对分页助手进行功能扩展。
3、对分页助手进行功能扩展
如果对分页助手的功能不满意,也可以扩展的方式改进。比如,增加构造“首页|上页|下页|末页”链接字串的方法,增加页码输入跳转方法,改造pageJumper页面选择跳转控件方法等。
功能扩展代码如下:
<?php
/**
* 文 件 名:extPager.php
* 说 明:分页类功能扩展
* 作 者:hegz
* 最后修改:2010/05/22
*
* 在项目目录下创建MyClass目录,用来保存扩展类。
* 使用方法:
* FLEA::loadClass('MyClass_extPager');
* $pager = & new MyClass_extPager();
*
*/
// 装载FLEA_Helper_Pager类库
FLEA::loadClass('FLEA_Helper_Pager');
// 为了方便使用FLEA::laodClass函数来装载扩展类,按照FleaPHP的命名规范来命名扩展类
class MyClass_extPager extends FLEA_Helper_Pager
{
/**
* 构造函数
*
*/
function MyClass_extPager(& $source, $currentPage, $pageSize = 20,
$conditions = null, $sortby = null) {
// 继承了父类的构造函数
parent::FLEA_Helper_Pager($source, $currentPage, $pageSize,
$conditions, $sortby, $basePageIndex = 1);
}
/**
* 生成一个页面选择跳转控件
* 跨平台适用,不用额外JavaScript脚本支持
*
* @param string $caption
* @param array $args
* @return string
* @sample: $pager->pageJumper('第 %u 页', null, null, array('type' => 'article'))
* 示例参数说明:
* 传入的数组参数第一个为控制器名,第二个为动作名,第三个为其它链接参数数组,
* 方便使用一个控制器控制来进行同一个页面多个信息板块的分页。
* $this->basePageIndex = 1 才能正常使用;
*/
function pageJumper($caption = '%u', $ctl = null, $act = null, $args = null) {
$out = "<SELECT name='pageJumper' size='1' οnchange='window.location=this.value'>\n";
for ( $i = 1; $i <= $this->pageCount; $i++ ) {
if ($this->currentPage == $i) {
$extra = "selected";
} else {
$extra = "";
}
$link = "http://" . $_SERVER['HTTP_HOST'];
if (isset($args)) {
$args['page'] = $i;
} else {
$args = array('page' => $i);
}
$link .= url($ctl, $act, $args);
$out .= "<OPTION VALUE='" . $link . "' $extra>";
$out .= sprintf($caption, $i) . "</OPTION>\n";
}
return $out .= "</SELECT>\n";
}
/**
* 获取分页情况
*
* @return sring
*/
function getPageStatus() {
return "第 " . $this->currentPageNumber . " 页/共 " . $this->lastPageNumber . " 页";
}
/**
* 获取"首页 | 上页 | 下页 | 未页"分页链接字串,
*
* @param string $ctl 控制器名
* @param string $act 动作名
* @param array $args 其它参数数组
* @sample: $pager->getPageLink(null, null, array('page' => 3, 'block' => 'article'))
* 示例参数说明:
* 传入的数组参数第一个为控制器名,第二个为动作名,第三个为其它链接参数数组,
* 方便使用一个控制器控制来进行同一页面多个信息板块的分页。
* $this->basePageIndex = 1 才能正常使用;
*/
function getPageLink($ctl = null, $act = null, $args = null)
{
if ($this->currentPage > 1) {
if (isset($args['page'])) {
$args['page'] = $this->firstPageNumber;
}
$link1 = url($ctl, $act, $args);
if (isset($args['page'])) {
$args['page'] = $this->prevPageNumber ;
}
$link2 = url($ctl, $act, $args);
$out = "<a href=\"" . $link1 . "\">首页</a> | ";
$out .= "<a href=\"" . $link2 . "\">上页</a>";
} else {
$out = "首页 | 上页";
}
if ($this->currentPage <= $this->pageCount -1) {
$out .= " | ";
if (isset($args['page'])) {
$args['page'] = $this->nextPageNumber ;
}
$link1 = url($ctl, $act, $args);
if (isset($args['page'])) {
$args['page'] = $this->lastPageNumber;
}
$link2 = url($ctl, $act, $args);
$out .= "<a href=\"" . $link1 . "\">下页</a> | ";
$out .= "<a href=\"" . $link2 . "\">末页</a>";
} else {
$out .= " | 下页 | 末页";
}
return $out;
}
/**
* 生成分页码输入栏
*
* @param string $ctlName 控制器名称
* @param string $actName 动作名称
* @param array $args 链接参数数组
* @return HTML代码
*/
function pageInput($ctlName = null, $actName = null, $args = null)
{
$ui = & FLEA::initWebControls();
return '输入跳转页码:' . $ui->control(
"textbox",
'page',
array(
'size' => '3',
'value'=> null,
//'class' => 'input',
//'onchange' => 'fnOnPageChanged(this.value)',
'onkeydown' => "if(event.keyCode==13) {window.location='" . url($ctlName, $actName, $args). "&page='+this.value; return false;}"
),
true
);
}
}
?>
下面讲讲其使用方法。
首先,准备好模板文件。其分页相关代码如下所示:
{{ $cutPageStr }}
接着编写后台PHP代码。如下面所示:
if (isset($_GET['page'])) {
$page = (int)$_GET['page'];
} elseif (isset($_POST['page'])) {
$page = (int)$_POST['page'];
} else {
$page = 1;
}
// 装载extPager类
FLEA::loadClass('MyClass_extPager');
// 获取Smarty实例句柄
$tpl = & $this->_getView();
$conditions = array(
array('uid', $this->user['UID'], '='),
);
$tblArt = & FLEA::getSingleton('Table_Articles');
$pager = & new MyClass_extPager($this->_tblArt, $page, 15, $conditions, 'art_id DESC');
$rows = $pager->findAll();
$cutPageStr = $pager->getPageLink('Article', null, array('page' => $page)) . " " . $pager->getPageStatus() . " " . $pager->pageInput('Article') . " 跳转到" . $pager->pageJumper('第 %u 页', 'Article');
$tpl->assign('lists', $rows);
$tpl->assign('cutPageStr', $cutPageStr);
$tpl->display('article_list.tpl');
装载extPager扩展类后,就不需要再装入分页助手类。
同时,由于增加了输入页码跳转功能后,代码:
$page = (isset($_GET['page']) ? (int)$_GET['page'] : 1;
需要修改为:
if (isset($_GET['page'])) {
$page = (int)$_GET['page'];
} elseif (isset($_POST['page'])) {
$page = (int)$_POST['page'];
} else {
$page = 1;
}
以适应发展变化的需要。
结语
讲解上面的几个分页方法占用了我大半天的休息时间。由于篇幅所限,时间精力不允许,可能讲的不够深入。同学们如果要透彻了解其分页精义,看完本文后,可以回去揣摩分析相关源代码。