[转载]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("&amp;", $linkextra);
  if($linkextra) {
    $linkextra .= "&amp;";
  }

  // 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) . "\">&laquo; 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 &raquo;</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("&amp;", $linkextra);
  if($linkextra) {
    $linkextra .= "&amp;";
  }

  ...
?>

这将导致字符串search= search &color= color被附加到所有导航链接,因此这些值将保留在页面之间。

参考文献

PHP: Iterators

版权

原文地址:https://www.the-art-of-web.com/php/pagination/

posted @ 2022-10-05 07:41  夏目贵志ㅤ  阅读(9)  评论(0编辑  收藏  举报