Логика для разбивки на страницы, как 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 .= '…'; // 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 .= '…'; // 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
Это то, что я делаю для своей разбивки на страницы.
$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 .= ' <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 .= ' <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).'">«</a>';
} else {
$sL = 'First';
$sN = '«';
}
if ($pSel < $ePage) {
$eL = '<a href="#" id="'.$pTot.'">End</a>';
$eN = '<a href="#" id="'.($pSel+1).'">»</a>';
} else {
$eL = 'End';
$eN = '»';
}
$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]