Может ли кто-нибудь предоставить код или псевдокод для создания ссылок подкачки в StackOverflow?
Я продолжаю ломать голову, но не могу придумать достойного способа построить динамические ссылки, которые всегда показывают 2 страницы вокруг текущей, а также первую и последнюю.
Пример: 1 ... 5 6 7 ... 593





Что ж, если вы знаете текущую страницу, довольно тривиально просто вычесть число на 1 и добавить его на 1, затем сверить эти числа с границами и всегда отображать первую и последнюю страницу, а затем, если они не находятся в последовательности , добавьте эллипсы.
Или вы спрашиваете об общем количестве страниц и определении текущего номера страницы ...?
Элементы управления обычно показывают элементы управления для: P1, Pn, Pc (текущая страница), Pc + 1, Pc-1. Единственный раз, когда это изменяется, происходит на обоих концах диапазона пейджинга {Pc <P3 or Pc> (Pn-3)}
numPages = ceiling(totalRecords / numPerPage)
Если у вас есть 4 или меньше, то выйдите из этого пункта, потому что, согласно приведенным выше правилам, разбиение на страницы всегда будет фиксированным (P1, P2, Pn-1, Pn), где фактически будет Pc
иначе у вас есть три "состояния"
а. (Pc <P3) - так показывать P1, P2, P3, Pn, Next. Если Pc> 1, показывать ссылку «prev» перед P1.
б. (Pc> Pn - 2), поэтому покажите Prev, P1, Pn - 2, Pn -1, Pn, покажите ссылку Next, если Pc <Pn
c. Показать Prev, P1, Pc -1, Pc, Pc +1, Pn, Next
Легко, как пирог в псевдокоде. Циклы могут стать немного неприятными при реализации, поскольку вам нужно выполнить некоторые итерации, чтобы сгенерировать ссылки.
Редактировать: Конечно, Prev и Next идентичны Pc +/- 1
public void PageLinks(int currentPage, int lastPage) {
if (currentPage > 2)
Add('[1]', '...');
for(int i=Math.Max(1, currentPage-1); i< Math.Min(currentPage+1, lastPage); i++)
Add('[i]');
if (currentPage < lastPage-1)
Add('...', '[lastpage]');
}
lastPage рассчитывается как Math.Ceiling (totalRecords / RecordsPerPage).
Хм. фактически, если текущая страница равна 3, она все равно показывает [1] ... [2] [3] [4] ... [xxx] Я думаю, что в этом случае эллипсы излишни. Но вот как это работает.
Обновлено: предварительный просмотр правильно форматирует кодовый блок, почему он искажается? конечно, это просто псевдокод .... но все же ....
Уже есть несколько других ответов, но я хотел бы показать вам подход, который я использовал для его решения: Во-первых, давайте посмотрим, как Stack Overflow обрабатывает обычные и крайние случаи. На каждой из моих страниц отображается 10 результатов, поэтому, чтобы узнать, что она делает для 1 страницы, найдите тег, в котором меньше 11 записей: удобство использования работает сегодня. Мы видим, что ничего не отображается, что имеет смысл.
Как насчет 2 страниц? Найдите тег, содержащий от 11 до 20 записей (emacs работает сегодня). Мы видим: «1 2 Next» или «Prev 1 2», в зависимости от того, на какой странице мы находимся.
3 страницы? «1 2 3 ... 3 Далее», «Назад 1 2 3 Далее» и «Назад 1 ... 2 3». Интересно, что мы видим, что сам Stack Overflow не очень хорошо справляется с этим пограничным случаем: он должен отображать «1 2 ... 3 Next»
4 страницы? «1 2 3 ... 4 Далее», «Назад 1 2 3 ... 4 Далее», «Назад 1 ... 2 3 4 Далее» и «Назад 1 ... 3 4»
Наконец, давайте посмотрим на общий случай, N страниц: «1 2 3 ... N Next», «Prev 1 2 3 ... N Next», «Prev 1 ... 2 3 4 ... N Next», «Назад 1 ... 3 4 5 ... N Далее» и т. д.
Давайте обобщим, основываясь на том, что мы видели: Алгоритм, похоже, имеет следующие общие черты:
Давайте проигнорируем крайний случай отдельной страницы и сделаем хорошую первую попытку алгоритма: (Как уже упоминалось, код для фактической печати ссылок был бы более сложным. Представьте себе каждое место, где мы помещаем номер страницы, Prev или Next как вызов функции, которая вернет правильный URL.)
function printPageLinksFirstTry(num totalPages, num currentPage)
if ( currentPage > 1 )
print "Prev"
print "1"
print "..."
print currentPage - 1
print currentPage
print currentPage + 1
print "..."
print totalPages
if ( currentPage < totalPages )
print "Next"
endFunction
Эта функция работает нормально, но не учитывает, находится ли мы рядом с первой или последней страницей. Глядя на приведенные выше примеры, мы хотим отображать ... только если текущая страница находится на расстоянии двух или более единиц.
function printPageLinksHandleCloseToEnds(num totalPages, num currentPage)
if ( currentPage > 1 )
print "Prev"
print "1"
if ( currentPage > 2 )
print "..."
if ( currentPage > 2 )
print currentPage - 1
print currentPage
if ( currentPage < totalPages - 1 )
print currentPage + 1
if ( currentPage < totalPages - 1 )
print "..."
print totalPages
if ( currentPage < totalPages )
print "Next"
endFunction
Как видите, здесь есть дублирование. Мы можем продолжить и очистить это для удобочитаемости:
function printPageLinksCleanedUp(num totalPages, num currentPage)
if ( currentPage > 1 )
print "Prev"
print "1"
if ( currentPage > 2 )
print "..."
print currentPage - 1
print currentPage
if ( currentPage < totalPages - 1 )
print currentPage + 1
print "..."
print totalPages
if ( currentPage < totalPages )
print "Next"
endFunction
Осталось всего две проблемы. Во-первых, мы неправильно распечатываем одну страницу, а во-вторых, мы распечатаем «1» дважды, если мы на первой или последней странице. Давайте очистим их за один присест:
function printPageLinksFinal(num totalPages, num currentPage)
if ( totalPages == 1 )
return
if ( currentPage > 1 )
print "Prev"
print "1"
if ( currentPage > 2 )
print "..."
print currentPage - 1
if ( currentPage != 1 and currentPage != totalPages )
print currentPage
if ( currentPage < totalPages - 1 )
print currentPage + 1
print "..."
print totalPages
if ( currentPage < totalPages )
print "Next"
endFunction
На самом деле, я соврал: у нас осталась одна проблема. Когда у вас есть как минимум 4 страницы, и вы находитесь на первой или последней странице, вы получаете дополнительную страницу на вашем дисплее. Вместо «1 2 ... 10 Next» вы получите «1 2 3 ... 10 Next». Чтобы точно соответствовать тому, что происходит в Stack Overflow, вам нужно проверить эту ситуацию:
function printPageLinksFinalReally(num totalPages, num currentPage)
if ( totalPages == 1 )
return
if ( currentPage > 1 )
print "Prev"
print "1"
if ( currentPage > 2 )
print "..."
if ( currentPage == totalPages and totalPages > 3 )
print currentPage - 2
print currentPage - 1
if ( currentPage != 1 and currentPage != totalPages )
print currentPage
if ( currentPage < totalPages - 1 )
print currentPage + 1
if ( currentPage == 1 and totalPages > 3 )
print currentPage + 2
print "..."
print totalPages
if ( currentPage < totalPages )
print "Next"
endFunction
Надеюсь, это поможет!
Спасибо за псевдокод, и здесь он реализован в Thymeleaf с правками @MrRogers gist.github.com/chotchki/8162634
Это мой подход к созданию ссылки для пейджинга. Следующий код Java - это просто псевдо.
package com.edde;
/**
* @author Yang Shuai
*/
public class Pager {
/**
* This is a method used to display the paging links(pagination or sometimes called pager).
* The totalPages are the total page you need to display. You can get this value using the
* formula:
*
* total_pages = total_records / items_per_page
*
* This methods is just a pseudo-code.
*
*
* @param totalPages how many pages you need to display
* @param currentPage you are in which page now
*/
public static void printPageLinks(int totalPages, int currentPage) {
// how many pages to display before and after the current page
int x = 2;
// if we just have one page, show nothing
if (totalPages == 1) {
return;
}
// if we are not at the first page, show the "Prev" button
if (currentPage > 1) {
System.out.print("Prev");
}
// always display the first page
if (currentPage == 1) {
System.out.print(" [1]");
} else {
System.out.print(" 1");
}
// besides the first and last page, how many pages do we need to display?
int how_many_times = 2 * x + 1;
// we use the left and right to restrict the range that we need to display
int left = Math.max(2, currentPage - 2 * x - 1);
int right = Math.min(totalPages - 1, currentPage + 2 * x + 1);
// the upper range restricted by left and right are more loosely than we need,
// so we further restrict this range we need to display
while (right - left > 2 * x) {
if (currentPage - left < right - currentPage) {
right--;
right = right < currentPage ? currentPage : right;
} else {
left++;
left = left > currentPage ? currentPage : left;
}
}
// do we need display the left "..."
if (left >= 3) {
System.out.print(" ...");
}
// now display the middle pages, we display how_many_times pages from page left
for (int i = 1, out = left; i <= how_many_times; i++, out++) {
// there are some pages we need not to display
if (out > right) {
continue;
}
// display the actual page
if (out == currentPage) {
System.out.print(" [" + out + "]");
} else {
System.out.print(" " + out);
}
}
// do we need the right "..."
if (totalPages - right >= 2) {
System.out.print(" ...");
}
// always display the last page
if (currentPage == totalPages) {
System.out.print(" [" + totalPages + "]");
} else {
System.out.print(" " + totalPages);
}
// if we are not at the last page, then display the "Next" button
if (currentPage < totalPages) {
System.out.print(" Next");
}
System.out.println();
}
public static void main(String[] args) {
// printPageLinks(50, 3);
help(500);
}
public static void test(int n) {
for (int i = 1; i <= n; i++) {
printPageLinks(n, i);
}
System.out.println("------------------------------");
}
public static void help(int n) {
for (int i = 1; i <= n; i++) {
test(i);
}
}
public static void help(int from, int to) {
for (int i = from; i <= to; i++) {
test(i);
}
}
}
Вот мой алгоритм. Это действительно здорово работает:
// Input
total_items // Number of rows, records etc. from db, file or whatever
per_page // num items per page
page // current page
visible_pages // number of visible pages
// Calculations
lastPage = ceil(total_items / per_page);
prevPage = page - 1 < 1 ? 0 : page - 1;
nextPage = page + 1 > lastPage ? 0 : page + 1;
halfpages = ceil(visible_pages / 2);
startPage = page - halfpages < 1 ? 1 : page - halfpages;
endPage = startPage + visible_pages - 1;
if (endPage > lastPage) {
startPage -= endPage - lastPage;
startPage = startPage < 1 ? 1 : startPage;
endPage = startPage + visible_pages > lastPage ? lastPage : startPage + visible_pages - 1;
}
// Output
lastPage // Total number of pages
prevPage // Previous page number (if 0 there is no prev page)
nextPage // Next page number (if 0 there is no next page)
startPage // First visible page
endPage // Last visible page
Итак, вы можете сделать такой пейджер:
if prevPage
[1] [prevPage]
endif
[startPage] ... [endPage]
if nextPage
[nextPage] [lastPage]
endif
или настройте все, что вам нравится.
Хорошо, спасибо. Единственное, что я изменил, - это то, что "..." выглядит немного глупо в нескольких ситуациях, поэтому я добавил. if (totalPages> 3 and currentPage> 3) print "..." и if (totalPages> 3 and currentPage <totalPages - 2) print "..." спасибо за помощь