문제

StackOverflow의 페이징 링크가 생성되는 방법에 대한 코드나 의사 코드를 제공할 수 있습니까?

계속 머리를 쥐어짜고 있지만 항상 현재 페이지와 첫 페이지와 마지막 페이지를 중심으로 2페이지를 표시하는 동적 링크를 구축하는 적절한 방법이 생각나지 않습니다.

예: 1 ... 5 6 7 ... 593

도움이 되었습니까?

해결책

이미 몇 가지 다른 답변이 있지만 이를 해결하기 위해 취한 접근 방식을 보여 드리고 싶습니다.먼저 Stack Overflow가 일반 케이스와 엣지 케이스를 어떻게 처리하는지 확인해 보겠습니다.각 페이지에는 10개의 결과가 표시되므로 1페이지에 대해 어떤 작업을 수행하는지 알아보려면 항목이 11개 미만인 태그를 찾으세요. 유용성 오늘 일해요.아무것도 표시되지 않는 것을 볼 수 있습니다. 이는 의미가 있습니다.

2페이지는 어떻습니까?11~20개 항목이 있는 태그를 찾습니다(이맥스 오늘 일합니다).우리는보다:"1 2 다음" 또는 "이전 1 2", 우리가 현재 있는 페이지에 따라 다릅니다.

3페이지?"1 2 3 ...3 다음", "이전 1 2 3 다음", "이전 1 ...2 3".흥미롭게도 Stack Overflow 자체는 이러한 극단적인 경우를 잘 처리하지 못한다는 것을 알 수 있습니다."라고 표시되어야 합니다.1 2 ...3 다음"

4페이지?"1 2 3 ...4 다음", "이전 1 2 삼 ...4 다음", "이전 1 ...2 3 4 다음" 및 "이전 1 ...삼 4"

마지막으로 일반적인 경우인 N 페이지를 살펴보겠습니다."1 2 3 ...N 다음", "이전 1 2 삼 ...N 다음", "이전 1 ...2 3 4 ...N 다음", "이전 1 ...삼 4 5 ...엔 다음' 등

우리가 본 내용을 바탕으로 일반화해 보겠습니다.알고리즘에는 다음과 같은 공통점이 있는 것 같습니다.

  • 첫 번째 페이지에 있지 않은 경우 이전 페이지로의 링크를 표시합니다.
  • 항상 첫 번째 페이지 번호를 표시합니다.
  • 항상 현재 페이지 번호를 표시합니다.
  • 항상 이 페이지 앞의 페이지와 이 페이지 뒤의 페이지를 표시합니다.
  • 항상 마지막 페이지 번호 표시
  • 마지막 페이지에 있지 않은 경우 다음으로의 링크를 표시합니다.

단일 페이지의 극단적인 경우를 무시하고 알고리즘을 처음으로 시도해 보겠습니다.(앞서 언급했듯이 실제로 링크를 인쇄하는 코드는 더 복잡합니다.올바른 URL을 반환하는 함수 호출로 페이지 번호, Prev 또는 Next를 배치하는 각 장소를 상상해 보세요.)

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 다음으로 "당신은"을 얻습니다1 2 3 ...10 다음".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인 경우 다음 링크를 표시합니다.

씨.이전, P1, Pc -1, Pc, Pc +1, Pn, 다음 표시

의사 코드에서는 파이처럼 쉽습니다.링크를 생성하기 위해 몇 가지 반복 작업을 수행해야 하므로 루프를 구현할 때 약간 지저분해질 수 있습니다.

편집하다:물론 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]이 경우 타원이 불필요하다고 생각합니다.하지만 그것이 작동하는 방식입니다.

편집하다:미리보기에서는 코드블록의 형식을 올바르게 지정했는데 왜 문제가 발생합니까?물론이죠, 그냥 의사코드일 뿐입니다....하지만 아직도....

이것이 페이징 링크를 만드는 나의 접근 방식입니다.다음과 같은 자바 코드 그냥 사이비일 뿐입니다.

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

또는 원하는 대로 맞춤설정하세요.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top