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

Какова логика разбиения страницы на страницы Google?

Мой 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 > 

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

Вот мой код:

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

Это то, что я делаю для своей разбивки на страницы.

 $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 хранят диапазон страниц, которые разбивают на страницы, чтобы сгенерировать.

Шаг 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 "; 

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

Это просто потрясающе! Я думаю, что у меня есть эта страничка, чтобы работать так, как я описал.
Пожалуйста, посмотрите и попробуйте здесь 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 находится между значением MidRange и 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)); // eg 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(); 

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

number_of_active_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)] + отдельная + страница + следующая_страница 
  < 1 ... 3 4 [5] 6 7 ... 184 > 

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

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

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

Это логика разбиения на страницы, которую я имею

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