【问题标题】:Logic behind pagination like google像谷歌一样的分页背后的逻辑
【发布时间】:2012-07-01 14:15:59
【问题描述】:

谷歌分页行为背后的逻辑是什么?

我的分页器是这样的:

[1]  2   3  ...  184   >
 <   1  [2]  3   4  ...  184   >
 <   1   2  [3]  4   5  ...  184   >
 <   1   2   3  [4]  5   6   ...  184   >
 <   1  ...  3   4  [5]  6    7   ...  184   >
 <   1  ...  4   5  [6]  7    8   ...  184   >
 <   1  ...  5   6  [7]  8    9   ...  184   >
 <   1  ...  6   7  [8]  9    10  ...  184   >

这是上述示例的实时版本:http://www.dev.thomaskile.me/?page=test-zone&module=Paginator
我知道为什么会这样;我已将当前页面每一侧显示的页码数量设置为两 (2)。

我宁愿数字的范围是这样的:

[1]  2   3   4   5   6   7   8   ...   184   >
 <   1  [2]  3   4   5   6   7   ...   184   >
 <   1   2  [3]  4   5   6   7   ...   184   >
 <   1   2   3  [4]  5   6   7   ...   184   >
 <   1  ...  3   4  [5]  6   7   ...   184   >
 <   1  ...  4   5  [6]  7   8   ...   184   >
 <   1  ...  5   6  [7]  8   9   ...   184   >    
 <   1  ...  6   7  [8]  9   10  ...   184   >

在开头和结尾我需要进行一些更改,但无法弄清楚如何使其成为简单的操作...
我也想让它变得灵活。这意味着我希望能够更改每一侧的所需页面数,并让脚本扩展并计算所有内容......

这是我目前的代码:

/**
 *  page controller buttons 
 *  @param str $this->querySting      href="URL string"
 *  @param str $this->pageIdentifier  $_GET['this-name']
 *  @param int $this->numPages        Total amount of pages
 *  @param int $this->midRange        Number of pages to show on each side of current page
 */

public function prevPage() 
{
    if ($this->currentPage > 1){ 
        $prevPage = ($this->currentPage - 1); 
        return '<a href="'.$this->queryString.'&'.$this->pageIdentifier.'='.$prevPage.'" class="prev">prev</a>'; 
    }
}
public function nextPage() 
{
    if ($this->currentPage < $this->numPages) { 
        $nextPage = $this->currentPage + 1;
        return '<a href="'.$this->queryString.'&'.$this->pageIdentifier.'='.$nextPage.'" class="next">next</a>';  
    }  
}
public function firstPage() 
{
    if ($this->currentPage > ($this->midRange + 1)) {  //  if number of pages between "currentPage" and "firstPage" exceeds $midRange with 1...
        $firstPage .= '<a href="'.$this->queryString.'&'.$this->pageIdentifier.'=1" class="first">1</a>';  //  ...show "first page"-link
        if ($this->currentPage > ($this->midRange + 2)) {   //  if number of pages between $currentPage and "first page" exceeds $midRange with more than 1
            $firstPage .= '&hellip;';  //  add "..." between "1st page"-link and first page in $range
        }
    }
    return $firstPage;
}
public function lastPage() 
{
    if ($this->currentPage < ($this->numPages - $this->midRange)) {  //  if number of pages between "currentPage" and "last page" is equal to $midRange
        if (($this->currentPage < ($this->numPages - $this->midRange) - 1)) {  //  if number of pages between $currentPage and "last page" exceeds $range with more than two
            $lastPage .= '&hellip;';  //  add "..." between "last page"-link and last page in $range
        } 
        $lastPage .= '<a href="'.$this->queryString.'&'.$this->pageIdentifier.'='.$this->numPages.'" class="last">'.$this->numPages.'</a>';   //  show "last page"-link
    }
    return $lastPage;
}

#  Range of pages between (prev first ...) and (... last next)
public function listPages() 
{
    for ($i = ($this->currentPage - $this->midRange); $i < (($this->currentPage + $this->midRange) + 1); $i++){
       if (($i > 0) && ($i <= $this->numPages))  //  if page number are within page range
       {
          if ($i == $this->currentPage) { $listPages .= '<a class="current">'.$i.'</a>'; }  //  if we're on current page
          else { $listPages .= '<a href="'.$this->queryString.'&'.$this->pageIdentifier.'='.$i.'">'.$i.'</a>'; }  //  if not current page
        }
    }
    return $listPages; 
}

【问题讨论】:

  • 很少有低代表用户提出与您一样高质量的问题。干杯!
  • 很好的问题描述。 1+
  • 对不起,伙计们,但我真的不知道所有这些费率是怎么回事...我可能应该花点时间了解一下这个网站是如何运作的,而不是仅仅问问题...我会调查的
  • 好问题,但为什么你不去你的老问题并选择一个答案?

标签: php oop class pagination


【解决方案1】:

这就是我为分页所做的。

$startPage = $currentPage - 4;
$endPage = $currentPage + 4;

if ($startPage <= 0) {
    $endPage -= ($startPage - 1);
    $startPage = 1;
}

if ($endPage > $totalPage)
    $endPage = $totalPage;

if ($startPage > 1) echo " First ... ";
for($i=$startPage; $i<=$endPage; $i++) echo " {$i} ";
if ($endPage < $totalPage) echo " ... Last ";

我相信我的代码是不言自明的,但我会尽量用简单的英语来解释它。首先,在生成 Pagination 之前需要知道两件事:$totalPage$currentPage

第 1 步:假设当前页面处于中档。 $startPage 和 $endPage 存储分页尝试生成的页面范围。

第二步:如果$startPage为负数,则需要补$endPage

第 3 步:如果 $endPage 超出 $totalPage,则 $endPage 是最后一页。

第 4 步:将分页生成 HTML。 (这取决于您希望您的分页看起来如何。我将简单地使用纯文本来表示我的分页)

if ($startPage > 1) echo " First ... ";
for($i=$startPage; $i<=$endPage; $i++) echo " {$i} ";
if ($endPage < $totalPage) echo " ... Last ";

修复了我之前逻辑的缺陷

$startPage = ($curPage < 5)? 1 : $curPage - 4;
$endPage = 8 + $startPage;
$endPage = ($totalPage < $endPage) ? $totalPage : $endPage;
$diff = $startPage - $endPage + 8;
$startPage -= ($startPage - $diff > 0) ? $diff : 0;

if ($startPage > 1) echo " First ... ";
for($i=$startPage; $i<=$endPage; $i++) echo " {$i} ";
if ($endPage < $totalPage) echo " ... Last ";

【讨论】:

  • 这能回答问题吗?
  • 好吧,我相信我的逻辑很简单,回答这个问题。
  • 我把你的建议放在我的下面:dev.thomaskile.me/?page=test-zone&module=Paginator(几乎只是复制/粘贴),一开始你几乎是正确的。但最后你可以清楚地看到区别......
  • 最后,将 startPage 设置为 -4 是不可能的。我们需要将其设置为特定的页码以将其锁定,以便可见的页数与开始时一样...
  • 我在最后看到了我的逻辑缺陷。我会尝试在不使用太多 if-else-elseif 的情况下修复它。我相信它可以通过一些数学来解决。
【解决方案2】:

这次谈话对我来说是一个很好的开始!但我想要一个更接近原始问题意图的分页器,即:
1) 可以包含在带有变量的函数中,以更改总页数、当前页数以及当前要显示的每一侧的页数。
2) 保持恒定的宽度,类似于原帖:

 <  [1]   2    3    4    5    6   7    ...   99   >
 <   1   [2]   3    4    5    6   7    ...   99   >
 <   1    2   [3]   4    5    6   7    ...   99   >
 <   1    2    3   [4]   5    6   7    ...   99   >
 <   1    2    3    4   [5]   6   7    ...   99   >
 <   1   ...   4    5   [6]   7   8    ...   99   >
 <   1   ...   5    6   [7]   8   9    ...   99   >
 <   1   ...   92   93  [94]  95  96   ...   99   >
 <   1   ...   93   94  [95]  96  97   98    99   >
 <   1   ...   93   94   95  [96] 97   98    99   >
 <   1   ...   93   94   95   96 [97]  98    99   >
 <   1   ...   93   94   95   96  97  [98]   99   >
 <   1   ...   93   94   95   96  97   98   [99]  >

3) 继续显示数字“2”而不是“...”,如果您有 1 ... 3
4) 最后也是一样。

这就是我所做的。我正在用不同的语言(coffeescript)进行编码,但无论如何它应该可以作为良好的 sudo 代码:

get_pages_array = (total_page, each_side, curr_page) ->
    if total_page <= (2*each_side)+5
        # in this case, too few pages, so display them all
        start_page = 1
        end_page = total_page
    else if curr_page<=each_side+3
        # in this case, curr_page is too close to the beginning
        start_page = 1
        end_page = (2*each_side)+3
    else if curr_page >= total_page - (each_side+2)
        # in this case, curr_page is too close to the end
        start_page = total_page - (2*each_side) - 2
        end_page = total_page
    else
        # regular case
        start_page = curr_page - each_side
        end_page = curr_page + each_side
    return_me = []
    if start_page> 1
        return_me.push "1"
    if start_page>2
        return_me.push "..."
    for x in [start_page..end_page]
        return_me.push x
    if end_page<total_page-1
        return_me.push "..."
    if end_page<total_page
        return_me.push total_page
    return return_me

我将这段代码用于 each_side = 2,所以我确信它可以工作。

编辑:根据@Vextil 的固定逻辑

【讨论】:

  • 我目前正在使用您的解决方案,但在 each_side 2. 修复它很容易,您只需将 end_page = each_side+5 替换为:end_page = (each_side * 2) + 3 而这个:@ 987654325@与:start_page = total_page - (each_side * 2) - 2
【解决方案3】:

这真是太棒了!我想我让这个分页器按照我描述的方式工作。
请在这里查看并尝试http://dev.thomaskile.me/?page=test-zone&module=Paginator 并告诉我...

经过大量的逻辑数学研究,我终于得出了这个结论:
为了使这种行为在不同级别上如此不同,必须有一些ifelsef-s 来分别处理每个级别的逻辑。我会尝试解释,但发现很难以一种好的方式做到......

这些是我正在谈论的级别:

  • 如果 currentPage == firstPage :
    计算从第 2 页开始在 currentPage 之后显示多少页。
    这个计算需要根据最多有多少页框来完成。 (中值是这里的关键因素)

    [1] 2   3    4    5    6    7    8   ...   184   >
    
  • elseif currentPage 介于 firstPage 和 midRange 值之间。
    将范围内的页面减少一页,以防止添加 prevPage 后将整个分页器向右移动。 计算要在 currentPage 之前和之后显示的页面,以保持整个页面的数量相等。

    <   1  [2]   3    4    5    6    7   ...   184   >
    <   1   2   [3]   4    5    6    7   ...   184   >
    <   1   2    3   [4]   5    6    7   ...   184   >
    
  • elseif midRange 值在每一侧都达到最大值。这意味着我们在某个地方的中间。
    中范围页面 + 当前页面 + 中范围页面。我猜很直接......

    <   1  ...   3    4   [5]   6    7   ...   184   >
                          ...
                          ...
                          ...
    <   1  ...  178  179 [180] 181  182  ...   184   >
    
  • elseif currentPage 介于 midRange 值和 lastPage
    几乎和一开始一样。不同之处在于计算一个静态页码以开始页面,然后计算在当前页面之前/之后显示的页面...
    (顺便说一句,这个周末我很头疼)

    <   1  ...  178  179  180 [181] 182  183   184   >
    <   1  ...  178  179  180  181 [182] 183   184   >
    <   1  ...  178  179  180  181  182 [183]  184   >
    
  • elseif currentPage == numPages(总页数)。 与 firstPage 操作几乎相同...计算需要多少页才能填满整个内容并计算从哪里开始...

我现在需要做的是让代码本身变得更好......

    <   1  ...  178  179  180  181  182  183  [184]  >

在我的情况下,“问题”是整个分页器应该根据 midRange 值计算所有内容,而不是其他任何东西。 为了让我在未来的任何项目中执行这个分页器,我所要做的就是:

    $paginator = new paginator((int));  //  e.g. number of total results from a db request

在大多数情况下,我可能需要添加个人查询字符串以确保 a href 正常工作:

    $paginator->set_queryString('my querystring');

仅此而已。我已经设置了几个像这样的可选函数:

    $paginator->set_resultsPerPage((int));
    $paginator->set_midRange((int));
    $paginator->set_pageIdentifier('querystring-pageNumber-identifier-name-for-get');  //  whatever I needed

最后我像这样显示分页器页面控制器:

    $paginator->pageController('full');  //  full, med, min for different styles.

如果这些都不够好,我可以像这样调用每个按钮:

    $paginator->prevPage();
    $paginator->firstPage();
    $paginator->listPages();
    $paginator->lastPage();
    $paginator->nextPage();
    $paginator->pageJumper();
    $paginator->perPageSelector();

【讨论】:

  • 你应该看看我下面的逻辑。我相信它可以满足您的需求。
【解决方案4】:

这是一个 Python 程序,展示了如何正确执行此操作:

def main():
    num_pages = 13
    page = 12

    window = 5
    start = page - window
    end = page + window - 1
    if start <= 0:
        end = end - start + 1
        start = 1
    if end > num_pages:
        end = num_pages
        start = max(end - (window * 2) + 1, 1)

    for no in range(start, end + 1):
        print "{}*".format(no) if page == no else no

if __name__ == '__main__':
    main()

【讨论】:

  • 不错的解决方案,但为什么 end = page + window - 1 而不是 end = page + window
【解决方案5】:

我假设您的分页结构如下:

number_of_active_page + 单独的(...) + page(184) + next_page(>)

您可以将 number_of_active_page 设置为 8 (包括 prev_page(

[1]  2   3   4   5   6   7   8         ...     184       >
[number_of_active_page(设置为 8)] + 单独 + page + next_page 
 <   1  ...  3   4  [5]  6   7         ...     184       >

【讨论】:

    【解决方案6】:

    Hear 是一个简单的分页显示示例:

    $paginationDisplay = ""; // Initialize the pagination output variable
    // This code runs only if the last page variable is not equal to 1, 
    // if it is only 1 page we require no paginated links to display
    if ($lastPage != "1"){
      // This shows the user what page they are on, and the total number of pages
      $paginationDisplay .= 'Page <strong>' . $pn . 
                '</strong> of ' . $lastPage. 'last';
      // If we are not on page 1 we can place the Back button
      if ($pn != 1) {
         $previous = $pn - 1;
         $paginationDisplay .=  '&nbsp;  <a href="' . 
                $_SERVER['PHP_SELF'] . '?pn=' . $previous . '"> Back</a> ';
        } 
        // Lay in the clickable numbers display here between the Back and Next links
        $paginationDisplay .= '<span>' . $centerPages . '</span>';
        // If we are not on the very last page we can place the Next button
        if ($pn != $lastPage) {
            $nextPage = $pn + 1;
            $paginationDisplay .=  '&nbsp;  <a href="' . 
                $_SERVER['PHP_SELF'] . '?pn=' . $nextPage . '"> Next</a> ';
        } 
    }
    

    【讨论】:

    • 欢迎来到 SO。您可以使用 4 个空格来创建一个代码块,并使用 2 个空格来分隔代码块中的一行。更多关于答案编辑器上的帮助链接。
    【解决方案7】:

    这是我的分页逻辑

    $pLinks = 5; // Links per page 
    $pMids = 3;  
    $pTot = 10; // Total page 
    $pSel = 1  // Selected page 
    
    if (($pSel <= $pMids) || ($pTot <= $pLinks)) {
        $sPage = 1;                
        $ePage = ($pTot <= $pLinks) ? $pTot : $pLinks;
    } else {
        $etPage = $pSel + ($pMids - 1);            
        $ePage = ($etPage <= $pTot) ? $etPage : $pTot;            
        $sPage = $ePage - ($pLinks - 1);            
    }
    
    if ($pSel > $sPage) {
        $sL = '<a href="#" id="1">First</a>';
        $sN = '<a href="#" id="'.($pSel-1).'">&laquo;</a>';
    } else {
        $sL = 'First';
        $sN = '&laquo;';
    }
    
    if ($pSel < $ePage) {
        $eL = '<a href="#" id="'.$pTot.'">End</a>';
        $eN = '<a href="#" id="'.($pSel+1).'">&raquo;</a>';
    } else {
        $eL = 'End';
        $eN = '&raquo;';
    }
    
    $pOptions = '';
    
    $pOptions .= '<span class="iPage">'.$pSel.'/'.$pTot.'</span>';
    $pOptions .= '<span class="renderFL">'.$sL.'</span>';
    $pOptions .= '<span class="renderPN">'.$sN.'</span>';
    
    for ($i = $sPage; $i <= $ePage; $i++) {
        if($i != $pSel) {
            $pOptions .= '<span><a href="#" id="'.$i.'">'.$i.'</a></span>';
        } else {
            $pOptions .= '<span class="selected">'.$i.'</span>';
        }
    }
    
    $pOptions .= '<span class="renderPN">'.$eN.'</span>';
    $pOptions .= '<span class="renderFL">'.$eL.'</span>';
    

    结果将如下所示:

    1  -> [1] 2 3 4 5
    2  -> 1 [2] 3 4 5
    3  -> 1 2 [3] 4 5
    ..
    5  -> 3 4 [5] 6 7
    6  -> 4 5 [6] 7 8
    ..
    8  -> 6 7 [8] 9 10
    9  -> 6 7 8 [9] 10
    10 -> 6 7 8 9 [10]
    

    【讨论】:

      猜你喜欢
      • 2016-11-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多