[转载]PHP:高级分页
一旦您使用 PHP 连接到数据库,您就会遇到这样的情况:您希望获得比单个页面上显示的更多的内容。
目前普遍存在的解决方案是将您的数据拆分为多个页面,同时显示导航链接以让人们在页面之间导航。
示范
在这里,我们创建了一个只有数字 1 到 150 的数据集,并仅使用下一节中显示的代码将它们分成每页 20 个块:
第1页| 2 | 3 ... 7 | 8 | 下一个 ”
1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20.
当您滚动浏览页面时,我们会调整链接以尽量保持它们紧凑。当您有数十页时,这一点更为重要。基本上,我们只显示位于任一端或当前所选页面的两个位置内的链接。
这里显示的数据只是数字,但实际上每个数字都代表来自查询、产品、搜索结果、照片、博客条目等的一行数据。
分页PHP源码
首先,我们需要准备我们的数据和一些基本变量。在上面的演示中,我们使用以下内容,但您可以将它们替换为真实数据:
<?PHP
$NUMPERPAGE = 20; // max. number of items to display per page
$this_page = "/php/pagination/";
$data = range(1, 150); // data array to be paginated
$num_results = count($data);
?>
然后我们使用以下代码来构建导航链接:
<?PHP
# Original PHP code by Chirp Internet: www.chirpinternet.eu
# Please acknowledge use of this code by including this header.
if(!isset($_GET['page']) || !$page = intval($_GET['page'])) {
$page = 1;
}
// extra variables to append to navigation links (optional)
$linkextra = [];
if(isset($_GET['var1']) && $var1 = $_GET['var1']) { // repeat as needed for each extra variable
$linkextra[] = "var1=" . urlencode($var1);
}
$linkextra = implode("&", $linkextra);
if($linkextra) {
$linkextra .= "&";
}
// build array containing links to all pages
$tmp = [];
for($p=1, $i=0; $i < $num_results; $p++, $i += $NUMPERPAGE) {
if($page == $p) {
// current page shown as bold, no link
$tmp[] = "<b>{$p}</b>";
} else {
$tmp[] = "<a href=\"{$this_page}?{$linkextra}page={$p}\">{$p}</a>";
}
}
// thin out the links (optional)
for($i = count($tmp) - 3; $i > 1; $i--) {
if(abs($page - $i - 1) > 2) {
unset($tmp[$i]);
}
}
// display page navigation iff data covers more than one page
if(count($tmp) > 1) {
echo "<p>";
if($page > 1) {
// display 'Prev' link
echo "<a href=\"{$this_page}?{$linkextra}page=" . ($page - 1) . "\">« Prev</a> | ";
} else {
echo "Page ";
}
$lastlink = 0;
foreach($tmp as $i => $link) {
if($i > $lastlink + 1) {
echo " ... "; // where one or more links have been omitted
} elseif($i) {
echo " | ";
}
echo $link;
$lastlink = $i;
}
if($page <= $lastlink) {
// display 'Next' link
echo " | <a href=\"{$this_page}?{$linkextra}page=" . ($page + 1) . "\">Next »</a>";
}
echo "</p>\n\n";
}
?>
显示分页数据
我们可以通过使用LimitIterator类来显示单个页面 - 当前选定的页面 - 数据:
<?PHP
$data = new \ArrayIterator($data); // NOT needed if $data is already an Iterator!
$it = new \LimitIterator($data, ($page - 1) * $NUMPERPAGE, $NUMPERPAGE);
try {
$it->rewind();
foreach($it as $row) {
echo $row; // display record
}
} catch(\OutOfBoundsException $e) {
echo "Error: Caught OutOfBoundsException";
}
?>
如果提供的初始值超出范围,try/catch 语句会阻止循环运行。例如,如果$page
为负数,或者对于数据集来说太大。如果您愿意,可以使用异常块将$page
变量设置回 1,然后运行循环。
将三个代码块连接在一起,你应该有一个工作的分页系统。请注意,您可能希望在某些部分添加或删除某些行 - 如评论中所述。
如果您不熟悉 PHP 中的迭代器,您可能会发现这篇文章很有启发性。
这种方法的一个警告是,如果您的查询很昂贵,并且没有缓存,那么您最好使用带有 OFFSET 和 LIMIT 的查询来选择要显示的行,而不是使用 LimitIterator 来选择要显示的行,并使用单独的 COUNT 查询来确定总数结果数。
包括额外的链接变量
当使用导航链接时,“额外变量”部分允许您定义要在页面之间传递的额外值。这可以是搜索关键字、过滤器设置、用户 ID 或其他内容。
变量需要使用urlencode
进行编码,并将作为 GET 变量传递 - 与page
变量一样。这是一个更充实的例子:
<PHP
...
$linkextra = [];
if(isset($_GET['search']) && $search = $_GET['search']) {
$linkextra[] = "search=" . urlencode($search);
}
if(isset($_GET['color']) && $color = $_GET['color']) {
$linkextra[] = "color=" . urlencode($color);
}
$linkextra = implode("&", $linkextra);
if($linkextra) {
$linkextra .= "&";
}
...
?>
这将导致字符串search= search &color= color
被附加到所有导航链接,因此这些值将保留在页面之间。