Algoritmo/pseudo-codice per creare collegamenti di paginazione?
Domanda
Qualcuno può fornire codice o pseudocodice per come vengono generati i collegamenti di paging su StackOverflow?
Continuo a tormentarmi ma non riesco a pensare a un modo decente per costruire i collegamenti dinamici che mostrino sempre le 2 pagine attorno a quella corrente, più la prima e l'ultima.
Esempio: 1 ... 5 6 7 ... 593
Soluzione
Ci sono già molte altre risposte, ma vorrei mostrarti l'approccio che ho adottato per risolverlo:Per prima cosa, vediamo come Stack Overflow gestisce i casi normali e i casi limite.Ognuna delle mie pagine visualizza 10 risultati, quindi per scoprire cosa fa per 1 pagina, trova un tag che abbia meno di 11 voci: usabilità funziona oggi.Possiamo vedere che non viene visualizzato nulla, il che ha senso.
Che ne dici di 2 pagine?Trova un tag che contenga da 11 a 20 voci (emacs funziona oggi).Vediamo:"1 2 Successivo" o "Prec. 1 2", a seconda della pagina in cui ci troviamo.
3 pagine?"1 2 3...3 Successivo", "Prec. 1 2 3 Successivo" e "Prec. 1...2 3".È interessante notare che possiamo vedere che Stack Overflow stesso non gestisce molto bene questo caso limite:dovrebbe essere visualizzato "1 2...3 Avanti"
4 pagine?"1 2 3...4 Successivo", "Prec. 1 2 3...4 Successivo", "Prec. 1...2 3 4 Successivo" e "Prec. 1...3 4"
Infine diamo un'occhiata al caso generale, N pagine:"1 2 3...N Avanti", "Prec. 1 2 3...N Avanti", "Prec. 1...2 3 4...N Avanti", "Prec. 1...3 4 5...N Avanti", ecc.
Generalizziamo in base a quanto visto:L’algoritmo sembra avere questi tratti in comune:
- Se non siamo nella prima pagina, visualizza il collegamento a Prec
- Visualizza sempre il numero della prima pagina
- Visualizza sempre il numero di pagina corrente
- Visualizza sempre la pagina prima di questa pagina e la pagina dopo questa pagina.
- Visualizza sempre l'ultimo numero di pagina
- Se non siamo nell'ultima pagina, visualizza il collegamento a Successivo
Ignoriamo il caso limite di una singola pagina e facciamo un buon primo tentativo con l'algoritmo:(Come è stato accennato, il codice per stampare effettivamente i collegamenti sarebbe più complicato.Immagina in ogni posto in cui inseriamo un numero di pagina, Prev o Next come una chiamata di funzione che restituirà l'URL corretto.)
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
Questa funzione funziona bene, ma non tiene conto se siamo vicini alla prima o all'ultima pagina.Guardando gli esempi sopra, vogliamo solo visualizzare il...se la pagina corrente è a due o più di distanza.
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
Come puoi vedere, qui abbiamo qualche duplicazione.Possiamo andare avanti e ripulirlo per la leggibilità:
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
Rimangono solo due problemi.Innanzitutto, non stampiamo correttamente una pagina e, in secondo luogo, stamperemo "1" due volte se siamo sulla prima o sull'ultima pagina.Puliamoli entrambi in una volta sola:
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
In realtà ho mentito:Abbiamo un problema rimanente.Quando hai almeno 4 pagine e sei sulla prima o sull'ultima pagina, ottieni una pagina in più sul tuo display.Invece di "1 2...10 Successivamente" ottieni "1 2 3...10 Avanti".Per abbinare esattamente ciò che sta succedendo su Stack Overflow, dovrai verificare questa situazione:
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
Spero che aiuti!
Altri suggerimenti
I controlli generalmente mostrano i controlli per:P1, Pn, Pc (pagina corrente), Pc+1, Pc-1.L'unica volta che questo cambia è alle estremità dell'intervallo di paginazione {Pc < P3 o Pc > (Pn-3)}
- Il primo passo è ovviamente calcolare il numero di pagine:
numPages = ceiling(totalRecords / numPerPage)
Se ne hai 4 o meno, a questo punto abbandona, perché, secondo le regole di cui sopra, la paginazione sarà sempre fissa (P1, P2, Pn-1, Pn), dove in realtà uno sarà Pc
altrimenti hai tre "stati"
UN.(Pc < P3) - quindi mostra P1, P2, P3, Pn, Next Se Pc >1, mostra un collegamento 'prev' prima di P1.
B.(Pc > Pn - 2), quindi mostra Prev, P1, Pn - 2, Pn -1, Pn, mostra un collegamento Next se Pc < Pn
C.Mostra Prec, P1, Pc -1, Pc, Pc +1, Pn, Successivo
Facile come una torta in pseudo codice.I loop possono diventare un po' fastidiosi una volta implementati poiché è necessario eseguire alcune iterazioni per generare i collegamenti.
Modificare:Ovviamente Prev e Next sono identici a Pc +/- 1
Bene, se conosci la pagina corrente, è piuttosto banale sottrarre semplicemente il numero per 1 e aggiungerlo per 1, quindi controlla quei numeri rispetto ai limiti e visualizza sempre la prima e l'ultima pagina, quindi se non sono in sequenza , aggiungi i puntini di sospensione.
Oppure stai chiedendo come ottenere il numero totale di pagine e determinare il numero di pagina corrente...?
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 viene calcolato come Math.Ceiling(totalRecords/RecordsPerPage).
hmmm.In realtà, nel caso in cui CurrentPage sia 3, mostra ancora [1] ... [2] [3] [4] ... [xxx] Penso che le ellissi siano superflue in quel caso.Ma è così che funziona.
Modificare:l'anteprima formatta correttamente il blocco di codice, perché viene danneggiato?certo, è solo pseudocodice....ma comunque....
Questo è il mio approccio per creare un collegamento di paging.Il seguente codice Java è solo uno pseudo.
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);
}
}
}
Ecco il mio algoritmo che funziona davvero bene:
// 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
Quindi puoi fare un cercapersone come questo:
if prevPage
[1] [prevPage]
endif
[startPage] ... [endPage]
if nextPage
[nextPage] [lastPage]
endif
o personalizza quello che preferisci.