Подтвердить что ты не робот

Логика для разбивки на страницы, как Google

Какова логика Google pagination bahviour?

Мой paginator выглядит примерно так:

[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.
Я знаю, почему это происходит; Я установил количество pagenumbers для отображения на каждой стороне текущей страницы до двух (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   >

В начале и в конце мне нужно внести изменения, но не могу понять, как сделать его легкой операцией...
Я хотел бы также сделать его гибким. Значение Я хотел был бы иметь возможность изменить количество разыскиваемых страниц с каждой стороны, и иметь script расширить и claculate все это...

Вот мой код:

/**
 *  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; 
}
4b9b3361

Ответ 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 ";

Я считаю, что мой код сам объясняется, но я попытаюсь объяснить его на простом английском языке. Прежде всего, вам нужно знать две вещи, прежде чем вы сможете создать разбиение на страницы: $totalPage и $currentPage.

Шаг 1. Предположим, что текущая страница находится в середине диапазона. $startPage и $endPage хранят диапазон страницы, которую пытается сгенерировать постраничная страница.

Шаг 2. Если значение $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 ";

Ответ 2

Этот разговор стал отличным началом для меня! Но я хотел, чтобы paginator приблизился к намерениям первоначального вопроса, что:
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-code:

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, так что, где я уверен, что он работает.

EDIT: фиксированная логика согласно @Vextil

Ответ 3

Это чисто удивительно! Я думаю, что у меня есть эта страница, чтобы работать так, как я описал. Пожалуйста, посмотрите и попробуйте здесь http://dev.thomaskile.me/?page=test-zone&module=Paginator и дайте мне знать...

После большого логического изучения математики я, наконец, пришел к такому выводу:
Чтобы сделать этот акт так по-разному на разных уровнях, должны быть некоторые if, elsef -s для обработки логики на каждом уровне отдельно. Я постараюсь объяснить, но с трудом делать это хорошо...

Это уровни, о которых я говорю:

  • Если currentPage == firstPage:
    Вычислите, сколько страниц будет отображаться после текущей страницы, начиная со второй страницы.
    Этот расчет необходимо было сделать в зависимости от того, сколько страниц будет там больше. (здесь среднее значение является средним значением)

    [1] 2   3    4    5    6    7    8   ...   184   >
    
  • elseif currentPage находится между значениями firstPage и midRange maxed out.
    Уменьшите количество страниц в диапазоне на единицу, чтобы предотвратить перемещение всего paginator вправо, как только будет добавлено значение 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 максимизируется с каждой стороны. Значит, мы где-то посередине. страницы midRange + текущие страницы + страницы MidRange. Довольно прямо, я думаю...

    <   1  ...   3    4   [5]   6    7   ...   184   >
                          ...
                          ...
                          ...
    <   1  ...  178  179 [180] 181  182  ...   184   >
    
  • elseif currentPage находится между значением среднего значения и lastPage
    Почти такой же, как в начале. Разница заключалась в том, чтобы вычислить статический pagenumber для запуска страниц, а затем рассчитать страницы для показа до/после текущей страницы...
    (это, кстати, было моей головной болью в эти выходные)

    <   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]  >

"Проблема" в моем случае состояла в том, что весь paginator должен вычислять все, основываясь на значении midRange и ничего больше. Для меня, чтобы выполнить этот paginator в любом из моих будущих проектов, все, что мне нужно сделать, это:

    $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

Я предполагаю, что ваша разбивка на страницы имеет следующую структуру:

number_of_active_page + отдельный (...) + страница (184) + next_page ( > )

Вы можете установить number_of_active_page значение 8 (include prev_page (<) + страницы (... и номер страницы)

[1]  2   3   4   5   6   7   8         ...     184       >
[number_of_active_page(set to 8)] + separate + page + next_page  
 <   1  ...  3   4  [5]  6   7         ...     184       >

Ответ 5

Здесь находится программа 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()

Ответ 6

Слушать - это простой пример отображения постраничного списка:

$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> ';
    } 
}

Ответ 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]