有人可以提供代码或伪代码来说明 StackOverflow 上的分页链接是如何生成的吗?
我一直在绞尽脑汁,但想不出一种体面的方法来构建动态链接,该链接始终显示当前的 2 页,以及第一页和最后一页。
例子:1 ... 5 6 7 ... 593
已经有其他几个答案,但我想向您展示我解决它的方法:首先,让我们看看 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
我希望这有帮助!
控件通常显示以下控件:P1、Pn、Pc(当前页面)、Pc+1、Pc-1。这种变化的唯一时间是在寻呼范围 {Pc < P3 或 Pc > (Pn-3)} 的任一端
numPages = ceiling(totalRecords / numPerPage)
如果你有 4 个或更少,此时退出,因为根据上述规则,分页总是固定的(P1,P2,Pn-1,Pn),其中一个实际上是 Pc
否则,你有三个“状态”
一种。(Pc < P3) - 所以显示 P1, P2, P3, Pn, Next 如果 Pc >1,在 P1 之前显示一个“上一个”链接。
湾。(Pc > Pn - 2), 所以显示 Prev, P1, Pn - 2, Pn -1, Pn, 如果 Pc < Pn 则显示 Next 链接
C。显示 Prev, P1, Pc -1, Pc, Pc +1, Pn, Next
在伪代码中像 Pie 一样简单。实现时循环可能会有点讨厌,因为您必须进行一些迭代才能生成链接。
编辑:当然 Prev 和 Next 与 Pc +/- 1 相同
好吧,如果您知道当前页面,只需将数字减 1,然后将其加 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)。
嗯。实际上,在 currentpage 为 3 的情况下,它仍然显示 [1]...[2][3][4]...[xxx] 我认为在这种情况下省略号是多余的。但这就是它的工作原理。
编辑:预览正确格式化代码块,为什么它会被破坏?当然,它只是伪代码......但仍然......
这是我制作分页链接的方法。以下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
或自定义您喜欢的任何内容。