Алгоритм / псевдокод для создания ссылок на страницы?

Может ли кто-нибудь предоставить код или псевдокод для создания ссылок подкачки в StackOverflow?

Я продолжаю ломать голову, но не могу придумать достойного способа построить динамические ссылки, которые всегда показывают 2 страницы вокруг текущей, а также первую и последнюю.

Пример: 1 ... 5 6 7 ... 593

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
18
0
11 975
6
Перейти к ответу Данный вопрос помечен как решенный

Ответы 6

Что ж, если вы знаете текущую страницу, довольно тривиально просто вычесть число на 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

Надеюсь, это поможет!

Хорошо, спасибо. Единственное, что я изменил, - это то, что "..." выглядит немного глупо в нескольких ситуациях, поэтому я добавил. if (totalPages> 3 and currentPage> 3) print "..." и if (totalPages> 3 and currentPage <totalPages - 2) print "..." спасибо за помощь

Mr Rogers 06.11.2009 02:28

Спасибо за псевдокод, и здесь он реализован в Thymeleaf с правками @MrRogers gist.github.com/chotchki/8162634

chotchki 28.12.2013 22:42

Это мой подход к созданию ссылки для пейджинга. Следующий код 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

или настройте все, что вам нравится.

Другие вопросы по теме