本来这篇文章是不想写的,要写早几年就应该写了,为甚么突然想起要写一篇这样的东西呢?无他,因为随着年岁的增长,近日发觉自己的记忆力下降得非常厉害,看过的东西转头即忘。莫非这是老年痴呆的先兆?因此赶紧记之,以作备忘。
开发系统时,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="删除" onclick="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' onchange='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; }
以适应发展变化的需要。
结语
讲解上面的几个分页方法占用了我大半天的休息时间。由于篇幅所限,时间精力不允许,可能讲的不够深入。同学们如果要透彻了解其分页精义,看完本文后,可以回去揣摩分析相关源代码。