Question

Quelqu'un peut-il fournir du code ou un pseudo-code sur la manière dont les liens de pagination sur StackOverflow sont générés ?

Je n'arrête pas de me creuser la tête, mais je n'arrive pas à penser à un moyen décent de créer des liens dynamiques qui affichent toujours les 2 pages autour de la page actuelle, ainsi que la première et la dernière.

Exemple: 1 ... 5 6 7 ... 593

Était-ce utile?

La solution

Il existe déjà plusieurs autres réponses, mais j'aimerais vous montrer l'approche que j'ai adoptée pour le résoudre :Tout d'abord, voyons comment Stack Overflow gère les cas normaux et les cas extrêmes.Chacune de mes pages affiche 10 résultats, donc pour savoir ce qu'elle fait pour 1 page, recherchez une balise qui comporte moins de 11 entrées : convivialité fonctionne aujourd'hui.On voit que rien n'est affiché, ce qui est logique.

Que diriez-vous de 2 pages ?Recherchez une balise contenant entre 11 et 20 entrées (emacs fonctionne aujourd'hui).Nous voyons:"1 2 Suivant" ou "Précédent 1 2", selon la page sur laquelle nous nous trouvons.

3 pages ?"1 2 3...3 Suivant", "Précédent 1 2 3 Suivant" et "Précédent 1 ...2 3".Fait intéressant, nous pouvons voir que Stack Overflow lui-même ne gère pas très bien ce cas extrême :il devrait afficher "1 2...3 Suivant"

4 pages ?"1 2 3...4 Suivant", "Précédent 1 2 3...4 Suivant", "Précédent 1 ...2 3 4 Suivant" et "Précédent 1 ...3 4"

Regardons enfin le cas général, N pages :"1 2 3...N Suivant", "Précédent 1 2 3...N Suivant", "Précédent 1 ...2 3 4...N Suivant", "Précédent 1 ...3 4 5...N Suivant", etc.

Généralisons à partir de ce que nous avons vu :L’algorithme semble avoir ces traits communs :

  • Si nous ne sommes pas sur la première page, affichez le lien vers Précédent
  • Afficher toujours le numéro de la première page
  • Toujours afficher le numéro de la page actuelle
  • Affichez toujours la page avant cette page et la page après cette page.
  • Afficher toujours le numéro de la dernière page
  • Si nous ne sommes pas sur la dernière page, affichez le lien vers Suivant

Ignorons le cas limite d'une seule page et faisons un bon premier essai avec l'algorithme :(Comme cela a été mentionné, le code permettant d’imprimer les liens serait plus compliqué.Imaginez chaque endroit où nous plaçons un numéro de page, Prev ou Next comme un appel de fonction qui renverra l'URL correcte.)

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

Cette fonction fonctionne bien, mais elle ne tient pas compte si l'on est proche de la première ou de la dernière page.En regardant les exemples ci-dessus, nous souhaitons uniquement afficher le...si la page actuelle est à deux ou plus.

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

Comme vous pouvez le constater, nous avons ici des dédoublements.Nous pouvons continuer et nettoyer cela pour plus de lisibilité :

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

Il ne reste que deux problèmes.Premièrement, nous n’imprimons pas correctement une page, et deuxièmement, nous imprimerons « 1 » deux fois si nous sommes sur la première ou la dernière page.Nettoyons ces deux éléments en une seule fois :

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 fait, j'ai menti :Il nous reste un problème.Lorsque vous avez au moins 4 pages et que vous êtes sur la première ou la dernière page, vous obtenez une page supplémentaire dans votre affichage.Au lieu de "1 2...10 Ensuite, « vous obtenez »1 2 3...10 Suivant".Pour correspondre exactement à ce qui se passe chez Stack Overflow, vous devrez vérifier cette situation :

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

J'espère que ça aide!

Autres conseils

Les contrôles affichent généralement des contrôles pour :P1, Pn, Pc (page courante), Pc+1, Pc-1.Le seul moment où cela change est aux deux extrémités de la plage de pagination {Pc < P3 ou Pc > (Pn-3)}

  • La première étape consiste évidemment à calculer le nombre de pages :

numPages = ceiling(totalRecords / numPerPage)

  • Si vous en avez 4 ou moins, abandonnez à ce stade, car, selon les règles ci-dessus, la pagination sera toujours fixe (P1, P2, Pn-1, Pn), où l'on sera en réalité Pc.

  • sinon, vous avez trois "états"

un.(Pc < P3) - donc afficher P1, P2, P3, Pn, Next Si Pc >1, afficher un lien 'prev' avant P1.

b.(Pc > Pn - 2), donc afficher Prev, P1, Pn - 2, Pn -1, Pn, afficher un lien Suivant si Pc < Pn

c.Afficher Précédent, P1, Pc -1, Pc, Pc +1, Pn, Suivant

Simple comme bonjour en pseudo-code.Les boucles peuvent devenir un peu désagréables lorsqu'elles sont implémentées car vous devez effectuer quelques itérations afin de générer les liens.

Modifier:Bien sur Prev et Next sont identiques à Pc +/- 1

Eh bien, si vous connaissez la page actuelle, il est assez trivial de simplement soustraire le nombre par 1 et de l'ajouter par 1, puis de vérifier ces nombres par rapport aux limites et d'afficher toujours la première et la dernière page, puis si elles ne sont pas dans l'ordre. , ajoutez les ellipses.

Ou demandez-vous d'obtenir le nombre total de pages et de déterminer le numéro de page actuel... ?

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 est calculé comme Math.Ceiling (totalRecords/RecordsPerPage).

hmmm.En fait, dans le cas où CurrentPage est 3, il montre toujours [1] ... [2] [3] [4] ... [xxx] Je pense que les ellipses sont superflues dans ce cas.Mais c'est comme ça que ça marche.

Modifier:l'aperçu formate correctement le bloc de code, pourquoi est-il mutilé ?bien sûr, c'est juste un pseudocode....mais reste....

C'est mon approche pour créer un lien de pagination.Ce qui suit Code Java n'est qu'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);
        }
    }

}

Voici mon algorithme qui fonctionne vraiment 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

Vous pouvez donc faire un pager comme ceci :

    if prevPage
    [1] [prevPage] 
    endif

    [startPage] ... [endPage] 

    if nextPage
    [nextPage] [lastPage] 
    endif

ou personnalisez ce que vous voulez.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top