Вопрос по php, oop, class, pagination, paginate – Логика за нумерацией страниц, как Google

28

Какова логика поведения страниц в Google?

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

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

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

Here is my code so far:

/**
 *  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; 
}
Просто исправлен недостаток моей логики. invisal
Отличное описание вопроса. 1+ Arash Milani
Редко можно видеть пользователей с низким уровнем репутации, задающих вопросы с таким же высоким качеством, как и у вас. Ура! Madara Uchiha♦
хороший вопрос, но почему вы не переходите к своему старому вопросу и не выбираете ответ? dynamic
Мне очень жаль, ребята, но я даже не знаю, о чем все эти ставки ... Мне, вероятно, стоит потратить время и выяснить, как работает этот сайт, а не просто задавать вопросы ... Я посмотрю на Это ThomasK

Ваш Ответ

7   ответов
1

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

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

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

  • If currentPage == firstPage :
    Calculate how many pages to show after currentPage starting from 2nd page.
    This calculation needed to be done based on how many page boxes there would be at the most. (midRange value is a key factor here)

    [1] 2   3    4    5    6    7    8   ...   184   >
    
  • elseif currentPage is in between firstPage and midRange value maxed out.
    Reduce pages in range by one to prevent moving the whole paginator to the right once prevPage is added. Calculate pages to show before and after currentPage to keep the amount of pages equal trough the whole thing.

    <   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 value is maxed out on each side. Meaning we're in the middle somewhere.
    midRange pages + the current page + midRange pages. Quite straight forward i guess...

    <   1  ...   3    4   [5]   6    7   ...   184   >
                          ...
                          ...
                          ...
    <   1  ...  178  179 [180] 181  182  ...   184   >
    
  • elseif currentPage is in between midRange value and lastPage
    Almost the same as in the beginning. Difference was to calculate a static pagenumber to start pages from, then calculate pages to show before/after current page...
    (this, by the way, has been my headache this weekend)

    <   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 (number of tatal pages). Pretty much same as firstPage operation... calculating how many pages needed to fill the whole thing up and calculate where to start from...

Что мне нужно сделать сейчас, это сделать сам код лучше ...

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

& Quot; проблема & quot; в моем случае было то, что весь 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();
Вы должны взглянуть на мою логику ниже. Я верю, что это делает то, что вы хотите.
5

Этот разговор стал для меня отличным началом! Но я хотел, чтобы 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» а не & quot; ... & quot; в случаях, когда у вас будет 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 & lt; & gt; 2. Исправить это легко, вам просто нужно заменитьend_page = each_side+5 С:end_page = (each_side * 2) + 3   И это:start_page = total_page - (each_side+4) С:start_page = total_page - (each_side * 2) - 2
0

Вот программа 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()
0

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

number_of_active_page + separate(...) + page(184) + next_page(>)

Вы можете установить number_of_active_page стать 8 (включая prev_page (& lt;) + страницы (... и номер страницы)

[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       >
-1

Это логика нумерации страниц

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

Это то, что я делаю для своей пагинации.

$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.

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

Step 2: Если$startPage отрицательно, то вам нужно наверстать$endPage.

Step 3: Если$endPage избыток$totalPage, затем$endPage это последняя страница

Step 4: Создание пагинации в HTML. (это зависит от вас, как вы хотите, чтобы выглядела ваша нумерация страниц. Я просто буду использовать простой текст для представления моей нумерации страниц)

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

Fixed flaw to my previous logic

$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 ";
Это отвечает на вопрос?
Я увидел недостаток моей логики в конце. Я постараюсь исправить это, не используя слишком много if-else-elseif. Я верю, что это можно решить с помощью математики.
Я положил ваше предложение прямо под моим здесь:dev.thomaskile.me/?page=test-zone&module=Paginator (почти только скопировал / вставил), и в начале ваш почти на месте. Но в конце вы ясно видите разницу ... ThomasK
Ну, я считаю, что моя логика проста и отвечу на вопрос.
В конце невозможно просто установить startPage на -4. Нам нужно установить конкретный номер страницы, чтобы заблокировать его, чтобы количество видимых страниц действовало как в начале ... ThomasK
-1

Слушайте простой пример отображения нумерации страниц:

$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> ';
    } 
}
Добро пожаловать в ТАК. Вы можете использовать 4 пробела для создания блока кода и 2 пробела для разбивки строки из блоков кода. Подробнее о справочной ссылке в редакторе ответов.

Похожие вопросы