Pregunta

¿Alguien puede proporcionar código o pseudocódigo sobre cómo se generan los enlaces de paginación en StackOverflow?

Sigo devanándome los sesos, pero no puedo pensar en una forma decente de crear enlaces dinámicos que siempre muestren las 2 páginas alrededor de la actual, más la primera y la última.

Ejemplo: 1 ... 5 6 7 ... 593

¿Fue útil?

Solución

Ya hay varias otras respuestas, pero me gustaría mostrarles el enfoque que tomé para resolverlo:Primero, veamos cómo Stack Overflow maneja casos normales y casos extremos.Cada una de mis páginas muestra 10 resultados, así que para saber qué hace para 1 página, busque una etiqueta que tenga menos de 11 entradas: usabilidad funciona hoy.Podemos ver que no se muestra nada, lo cual tiene sentido.

¿Qué tal 2 páginas?Busque una etiqueta que tenga entre 11 y 20 entradas (emacs funciona hoy).Vemos:"1 2 Siguiente" o "Anterior 1 2", dependiendo de en qué página estemos.

¿3 páginas?"1 2 3...3 Siguiente", "Anterior 1 2 3 Siguiente" y "Anterior 1...2 3".Curiosamente, podemos ver que Stack Overflow en sí no maneja muy bien este caso extremo:debería mostrar "1 2...3 Siguiente"

¿4 páginas?"1 2 3...4 Siguiente", "Anterior 1 2 3...4 Siguiente", "Anterior 1...2 3 4 Siguiente" y "Anterior 1...3 4"

Finalmente veamos el caso general, N páginas:"1 2 3...N Siguiente", "Anterior 1 2 3...N Siguiente", "Anterior 1...2 3 4...N Siguiente", "Anterior 1...3 4 5...N Siguiente", etc.

Generalicemos en base a lo que hemos visto:El algoritmo parece tener estos rasgos en común:

  • Si no estamos en la primera página, mostrar enlace a Anterior
  • Mostrar siempre el número de la primera página
  • Mostrar siempre el número de página actual
  • Muestre siempre la página anterior a esta página y la página posterior a esta.
  • Mostrar siempre el último número de página
  • Si no estamos en la última página, mostrar el enlace a Siguiente

Ignoremos el caso límite de una sola página y hagamos un buen primer intento con el algoritmo:(Como se mencionó, el código para imprimir los enlaces sería más complicado.Imagine cada lugar donde colocamos un número de página, Anterior o Siguiente, como una llamada de función que devolverá la URL correcta).

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

Esta función funciona bien, pero no tiene en cuenta si estamos cerca de la primera o de la última página.Mirando los ejemplos anteriores, solo queremos mostrar el...si la página actual está a dos o más de distancia.

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

Como puede ver, tenemos algunas duplicaciones aquí.Podemos seguir adelante y limpiarlo para que sea legible:

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

Sólo quedan dos problemas.Primero, no imprimimos correctamente una página y, segundo, imprimiremos "1" dos veces si estamos en la primera o la última página.Limpiemos ambos de una vez:

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

En realidad, mentí:Nos queda un problema pendiente.Cuando tiene al menos 4 páginas y está en la primera o la última página, obtiene una página adicional en su pantalla.En lugar de "1 2...10 Siguiente "obtienes"1 2 3...10 Siguiente".Para coincidir exactamente con lo que está sucediendo en Stack Overflow, deberá verificar esta situación:

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

¡Espero que esto ayude!

Otros consejos

Los controles generalmente muestran controles para:P1, Pn, Pc (página actual), Pc+1, Pc-1.La única vez que esto cambia es en cualquiera de los extremos del rango de paginación {Pc < P3 o Pc > (Pn-3)}

  • El primer paso es, obviamente, calcular el número de páginas:

numPages = ceiling(totalRecords / numPerPage)

  • Si tiene 4 o menos, abandone en este punto, porque, según las reglas anteriores, la paginación siempre será fija (P1, P2, Pn-1, Pn), donde en realidad uno será Pc.

  • de lo contrario, tienes tres "estados"

a.(Pc < P3): muestre P1, P2, P3, Pn, Siguiente Si Pc >1, muestre un enlace 'anterior' antes de P1.

b.(Pc > Pn - 2), entonces muestra Anterior, P1, Pn - 2, Pn -1, Pn, muestra un enlace Siguiente si Pc < Pn

C.Mostrar Anterior, P1, Pc -1, Pc, Pc +1, Pn, Siguiente

Tan fácil como Pie en pseudocódigo.Los bucles pueden volverse un poco desagradables cuando se implementan, ya que hay que iterar un poco para generar los enlaces.

Editar:Por supuesto, Anterior y Siguiente son idénticos a Pc +/- 1

Bueno, si conoces la página actual, es bastante trivial simplemente restar el número por 1 y sumarlo por 1, luego comparar esos números con los límites y mostrar siempre la primera y la última página, y si no están en secuencia , agrega las elipses.

¿O está preguntando acerca de cómo obtener el número total de páginas y determinar el número de página actual...?

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 se calcula como Math.Ceiling(totalRecords/RecordsPerPage).

mmm.En realidad, en el caso de que CurrentPage es 3, todavía muestra [1] ... [2] [3] [4] ... [xxx] Creo que las elipses son superfluas en ese caso.Pero así es como funciona.

Editar:la vista previa formatea el bloque de código correctamente, ¿por qué se estropea?claro, es solo pseudocódigo....pero aún....

Este es mi enfoque para hacer un enlace de paginación.La siguiente código java es solo un 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);
        }
    }

}

Aquí está mi algoritmo, funciona muy bien:

    // 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

Entonces puedes hacer un buscapersonas como este:

    if prevPage
    [1] [prevPage] 
    endif

    [startPage] ... [endPage] 

    if nextPage
    [nextPage] [lastPage] 
    endif

o personaliza lo que quieras.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top