How to do page navigation for many, many pages? Logarithmic page navigation

后端 未结 4 1109
闹比i
闹比i 2020-11-28 05:49

What\'s the best way of displaying page navigation for many, many pages?

(Initially this was posted as a how-to tip with my answer included in the question. I\'ve

相关标签:
4条回答
  • 2020-11-28 05:59

    Simplified version of "Logarithmic Page Navigation" in JavaScript:

    Generates dropdown menu. This sample just document.write's it but you can develop it further according to your need (add onChange, etc). Javascript conversion thanks to http://www.basereality.com/PHPToJavascript.

    <script>
    
        function paginationLink(p, page)
        {
            if (p == page)
                return '<option selected value="' + p + '">' + p + '</option>';
            return '<option value="' + p + '">' + p+ '</option>';
        }
    
        function paginationHTML(page, lastPage)
        {
            var LINKS_PER_STEP = 5;
    
            // Now calculate page links...
            var lastp1 = 1;
            var lastp2 = page;
            var p1 = 1;
            var p2 = page;
            var c1 = LINKS_PER_STEP + 1;
            var c2 = LINKS_PER_STEP + 1;
            var s1 = '';
            var s2 = '';
            var step = 1;
            var result = 0;
            while (true)
            {
                if (c1 >= c2)
                {
                    s1 += paginationLink(p1, page);
                    lastp1 = p1;
                    p1 += step;
                    c1--;
                }
                else
                {
                    s2 = paginationLink(p2, page) + s2;
                    lastp2 = p2;
                    p2 -= step;
                    c2--;
                }
                if (c2 == 0)
                {
                    step *= 10;
                    p1 += step - 1;         // Round UP to nearest multiple of $step
                    p1 -= (p1 % step);
                    p2 -= (p2 % step);   // Round DOWN to nearest multiple of $step
                    c1 = LINKS_PER_STEP;
                    c2 = LINKS_PER_STEP;
                }
                if (p1 > p2)
                {
                    result += s1 + s2;
                    if ((lastp2 > page) || (page >= lastPage))
                        return result;
                    lastp1 = page;
                    lastp2 = lastPage;
                    p1 = page + 1;
                    p2 = lastPage;
                    c1 = LINKS_PER_STEP;
                    c2 = LINKS_PER_STEP + 1;
                    s1 = '';
                    s2 = '';
                    step = 1;
                }
            }
        }
    
        document.write('Menu generated with JavaScript <select>' + paginationHTML(765, 5055))+'</select>';
    
    </script>
    
    0 讨论(0)
  • 2020-11-28 06:11

    I think of two alternatives of logarithmic pagination:

    1. If relevant, you could split your data in sections, chapters and books. This is the old way, when paper was king, and libraries made the job of internet. Some PDF documents still have that.

    2. You can offer a search box, ala Wikipedia, if someone wants to jump to the part of big-data where supercalifragilisticexpialidocious is mentioned.

    0 讨论(0)
  • 2020-11-28 06:13

    How about:

    a) add <-100 <-10 [pagination] +10> +100> instead of blow up the pagination itself

    b) offer a direct page input [# .. ] [ view ] , filter the input against the valid page range

    c) needs some proper coding, but: expand the inner, floating range by say +/-10, +/-25, +/-100 page instead of blowing up the complete paging range

    0 讨论(0)
  • 2020-11-28 06:16

    Here's my solution - use "Logarithmic Page Navigation":

    This can be achieved by having page numbers distributed logarithmically, according to distance from either the endpoints or the current page. Here's an example of what I mean:

    1 2 3 4 5 6 . 10 . 20 . 30 . 40 . 50 .. 100 .. 200 . 210 . 220 . 230 . 240 . 250 . 252 253 254 255 256 257 258 259 260 261 262 . 270 . 280 . 290 . 300 . 310 .. 400 .. 500 .. 600 .. 700 .. 800 .. 900 .. 950 . 960 . 970 . 980 . 990 . 995 996 997 998 999 1000

    Notice how in the gaps, numbering goes from 1s, to 10s, to 100s (etc.). (I use powers of 10, but in principle you could use a different scheme - powers of 2, say).

    I wrote some code that does this back in 2004, and thought I'd share it here. There are PHP and ASP versions, but the logic ought to be simple to translate into any language. Note that the bit at the bottom (in both cases) just displays some examples. Obviously the formatting will need customization to match your webpage (or application), so it's pretty basic here. Alter LINKS_PER_STEP in paginationHTML to determine how many numbers get displayed before the step size increases, as you move away from the endpoints or current page.

    For a more compact output you could also consider altering the code so that the numbering is not "dense" around the endpoints (i.e. dense only around the current page).

    Here's the code:

    PHP version:

    <?
    
    // Used by paginationHTML below...
    function paginationLink($p, $page, $URL)
    {
      if ($p==$page) return '<b style="color:#C0C0C0">' . $p . '</b>';
      return '<a href="' . $URL . $p . '">' . $p . '</a>';
    }
    
    
    // Used by paginationHTML below...
    function paginationGap($p1, $p2)
    {
      $x = $p2-$p1;
      if ($x==0) return '';
      if ($x==1) return ' ';
      if ($x<=10) return ' . ';
      if ($x<=100) return ' .. ';
      return ' ... ';
    }
    
    
    // URL requires the $page number be appended to it.
    // e.g. it should end in '&page=' or something similar.
    function paginationHTML($page, $lastPage, $URL)
    {
      $LINKS_PER_STEP = 5;
    
      // Nav buttons
    
      if ($page>1)
        $result = '<form action="' . $URL . '1" method="POST" style="display:inline"><input type="submit" value="&nbsp;|&lt;&nbsp;"></form>&nbsp;' .
                  '<form action="' . $URL . ($page-1) . '" method="POST" style="display:inline"><input type="submit" value="&nbsp;&lt;&nbsp;"></form>';
      else $result = '<input type="button" value="&nbsp;|&lt;&nbsp;" disabled>&nbsp;<input type="button" value="&nbsp;&lt;&nbsp;" disabled>';
    
      $result .= '&nbsp;&nbsp;' . $page . '&nbsp;&nbsp;';
      if ($page<$lastPage)
        $result .= '<form action="' . $URL . ($page+1) . '" method="POST" style="display:inline"><input type="submit" value="&nbsp;&gt;&nbsp;"></form>&nbsp;' .
                   '<form action="' . $URL . $lastPage . '" method="POST" style="display:inline"><input type="submit" value="&nbsp;&gt;|&nbsp;"></form>';
      else $result .= '<input type="button" value="&nbsp;&gt;&nbsp;" disabled>&nbsp;<input type="button" value="&nbsp;&gt;|&nbsp;" disabled>';
      $result .= "<br>";
    
      // Now calculate page links...
    
      $lastp1 = 1;
      $lastp2 = $page;
      $p1 = 1;
      $p2 = $page;
      $c1 = $LINKS_PER_STEP+1;
      $c2 = $LINKS_PER_STEP+1;
      $s1 = '';
      $s2 = '';
      $step = 1;
      while (true)
      {
        if ($c1>=$c2)
        {
          $s1 .= paginationGap($lastp1,$p1) . paginationLink($p1,$page,$URL);
          $lastp1 = $p1;
          $p1 += $step;
          $c1--;
        }
        else
        {
          $s2 = paginationLink($p2,$page,$URL) . paginationGap($p2,$lastp2) . $s2;
          $lastp2 = $p2;
          $p2 -= $step;
          $c2--;
        }
        if ($c2==0)
        {
          $step *= 10;
          $p1 += $step-1;         // Round UP to nearest multiple of $step
          $p1 -= ($p1 % $step);
          $p2 -= ($p2 % $step);   // Round DOWN to nearest multiple of $step
          $c1 = $LINKS_PER_STEP;
          $c2 = $LINKS_PER_STEP;
        }
        if ($p1>$p2)
        {
          $result .= $s1 . paginationGap($lastp1,$lastp2) . $s2;
          if (($lastp2>$page)||($page>=$lastPage)) return $result;
          $lastp1 = $page;
          $lastp2 = $lastPage;
          $p1 = $page+1;
          $p2 = $lastPage;
          $c1 = $LINKS_PER_STEP;
          $c2 = $LINKS_PER_STEP+1;
          $s1 = '';
          $s2 = '';
          $step = 1;
        }
      }
    }
    
    ?>
    
    <br><br><br>
    <?=paginationHTML(1,1,'?page=')?>
    
    <br><br><br>
    <?=paginationHTML(2,3,'?page=')?>
    
    <br><br><br>
    <?=paginationHTML(3,3,'?page=')?>
    
    <br><br><br>
    <?=paginationHTML(73,100,'?page=')?>
    
    <br><br><br>
    <?=paginationHTML(4,100,'?page=')?>
    
    <br><br><br>
    <?=paginationHTML(257,1000,'?page=')?>
    
    <br><br><br>
    <?=paginationHTML(7062,10555,'?page=')?>
    
    <br><br><br>
    <?=paginationHTML(22080,503456,'?page=')?>
    

    ASP version:

    <%
    
    ' Used by paginationHTML below...
    Function paginationLink(p, page, URL)
      if p=page then
        paginationLink = "<b style=""color:#C0C0C0"">" & p & "</b>"
      else
        paginationLink = "<a href=""" & URL & p & """>" & p & "</a>"
      end if
    End Function
    
    
    ' Used by paginationHTML below...
    Function paginationGap(p1, p2)
      Dim x
      x = p2-p1
      if x=0 then
        paginationGap = ""
      elseif x=1 then
        paginationGap = " "
      elseif x<=10 then
        paginationGap = " . "
      elseif x<=100 then
        paginationGap = " .. "
      else
        paginationGap = " ... "
      end if
    End Function
    
    
    ' URL requires the page number be appended to it.
    ' e.g. it should end in "&page=" or something similar.
    Function paginationHTML(page, lastPage, URL)
      const LINKS_PER_STEP = 5
      Dim p1, p2, c1, c2, s1, s2, lastp1, lastp2, step
    
      ' Nav buttons
      if page>1 then
        paginationHTML = "<form action=""" & URL & "1"" method=""POST"" style=""display:inline""><input type=""submit"" value=""&nbsp;|&lt;&nbsp;""></form>&nbsp;" & _
                        "<form action=""" & URL & (page-1) & """ method=""POST"" style=""display:inline""><input type=""submit"" value=""&nbsp;&lt;&nbsp;""></form>"
      else
        paginationHTML = "<input type=""button"" value=""&nbsp;|&lt;&nbsp;"" disabled>&nbsp;<input type=""button"" value=""&nbsp;&lt;&nbsp;"" disabled>"
      end if
      paginationHTML = paginationHTML & "&nbsp;&nbsp;" & page & "&nbsp;&nbsp;"
      if page<lastPage then
        paginationHTML = paginationHTML & "<form action=""" & URL & (page+1) & """ method=""POST"" style=""display:inline""><input type=""submit"" value=""&nbsp;&gt;&nbsp;""></form>&nbsp;" & _
                                        "<form action=""" & URL & lastPage & """ method=""POST"" style=""display:inline""><input type=""submit"" value=""&nbsp;&gt;|&nbsp;""></form>"
      else
        paginationHTML = paginationHTML & "<input type=""button"" value=""&nbsp;&gt;&nbsp;"" disabled>&nbsp;<input type=""button"" value=""&nbsp;&gt;|&nbsp;"" disabled>"
      end if
      paginationHTML = paginationHTML & "<br>"
    
      ' Now calculate page links...
    
      lastp1 = 1
      lastp2 = page
      p1 = 1
      p2 = page
      c1 = LINKS_PER_STEP+1
      c2 = LINKS_PER_STEP+1
      s1 = ""
      s2 = ""
      step = 1
      do
        if c1>=c2 then
          s1 = s1 & paginationGap(lastp1, p1) & paginationLink(p1, page, URL)
          lastp1 = p1
          p1 = p1+step
          c1 = c1-1
        else
          s2 = paginationLink(p2, page, URL) & paginationGap(p2, lastp2) & s2
          lastp2 = p2
          p2 = p2-step
          c2 = c2-1
        end if
        if c2=0 then
          step = step*10
          p1 = p1+step-1         ' Round UP to nearest multiple of step
          p1 = p1-(p1 mod step)
          p2 = p2-(p2 mod step)  ' Round DOWN to nearest multiple of step
          c1 = LINKS_PER_STEP
          c2 = LINKS_PER_STEP
        end if
        if p1>p2 then
          paginationHTML = paginationHTML & s1 & paginationGap(lastp1, lastp2) & s2
          if (lastp2>page) or (page>=lastPage) then exit do
          lastp1 = page
          lastp2 = lastPage
          p1 = page+1
          p2 = lastPage
          c1 = LINKS_PER_STEP
          c2 = LINKS_PER_STEP+1
          s1 = ""
          s2 = ""
          step = 1
        end if
      loop
    End Function
    
    %>
    
    
    <br><br><br>
    <%=paginationHTML(1,1,"?page=")%>
    
    <br><br><br>
    <%=paginationHTML(2,3,"?page=")%>
    
    <br><br><br>
    <%=paginationHTML(3,3,"?page=")%>
    
    <br><br><br>
    <%=paginationHTML(73,100,"?page=")%>
    
    <br><br><br>
    <%=paginationHTML(4,100,"?page=")%>
    
    <br><br><br>
    <%=paginationHTML(257,1000,"?page=")%>
    
    <br><br><br>
    <%=paginationHTML(7062,10555,"?page=")%>
    
    <br><br><br>
    <%=paginationHTML(22080,503456,"?page=")%>
    

    Javascript version (within complete test page):

    <!doctype html>
    <html>
    <head>
      <title>Logarithmic Pagination Demo</title>
      <style>
    
    body {background:#C0C0C0;font-family:Arial,Helvetica,sans-serif;font-size:16px;text-align:left}
    div {margin:0;padding:0}
    div#setupDiv {margin:40px;text-align:center}
    table#datarows {border-collapse:collapse;margin:40px auto}
    table#datarows th {padding:5px 10px;background:#80B0FF;color:#FFFFFF;border:2px solid #80B0FF;width:1000px;text-align:center}
    table#datarows td {padding:2px 10px;background:#FFFFFF;color:#D0D0D0;border:2px solid #80B0FF;width:1000px;text-align:left;font-style:italic}
    input.err {border:2px solid #FF0000;background-color:#FFF0F0}
    form.pager {display:table;margin:0 auto;padding:20px;border:2px solid #E0E0E0;border-radius:10px;background-color:#D0D0D0;text-align:left;white-space:nowrap}
    form#pager1 {margin-top:40px}
    form#pager2 {margin-bottom:60px}
    form.pager div {display:table-cell;vertical-align:middle;padding:0 20px;white-space:nowrap}
    form.pager div + div {border-left:2px solid #E0E0E0}
    form.pager div.plinks {padding:0;border:0 none;font-size:14px;line-height:24px;max-width:800px;white-space:normal}
    form.pager div.plinks b {display:inline-block;vertical-align:bottom;font-size:24px;line-height:21px;height:24px;overflow:hidden;color:#808080}
    form.pager div.plinks a {text-decoration:none;color:black}
    form.pager div.plinks a:hover {color:#0000FF;font-weight:bold}
    form.pager div.plinks + div {border:0 none}
    
      </style>
      <script>
    
    var NumPages, RecsPerPage, els1, els2, plinks1, plinks2;
    
    function setupClick()
    {
      var el, n, r;
      el = document.getElementById("NumPages");
      el.className = ((n = (el.value >>> 0)) ? "" : "err");
      el = document.getElementById("RecsPerPage");
      el.className = ((r = (el.value >>> 0)) ? "" : "err");
      if (n&&r) { NumPages = n; RecsPerPage = r; setupServerPage(); }
    }
    
    // This function sets up what would normally be part of the server's HTML output.
    function setupServerPage()
    {
      var totRecs = NumPages * RecsPerPage, tbdy = document.getElementById("datarows").tBodies[0], l = tbdy.rows.length;
      document.getElementById("plength1").innerHTML = document.getElementById("plength2").innerHTML = totRecs + " record" + ((totRecs===1)?"":"s") + "<br>" + NumPages + " page" + ((NumPages===1)?"":"s");
      els1["pcount"].value = els2["pcount"].value = NumPages;
      while (l>RecsPerPage) tbdy.deleteRow(--l);
      while (l<RecsPerPage) tbdy.insertRow(l++).insertCell(0).innerHTML = "Some data...";
      pageNavigate(1);
    }
    
    // This would be handled by a return trip to the server, if not using AJAX.
    function pageClick(e)
    {
      e = e||window.event;
      var s = e.target||e.srcElement, n, p, el;
      if (s.tagName==="A") { n = (p = s.href).lastIndexOf("=")+1; pageNavigate(p.substring(n) >>> 0); return false; }
      else if ((s.tagName!=="INPUT")||(s.type!=="submit")) return;
      if (!(n = s.name)) { p = ((el = this.elements["p"]).value >>> 0); if ((p<=0)||(p>NumPages)) { el.className = "err"; return false; }}
      else if (n==="p1") p = 1;
      else if (n==="pprev") p = (this.elements["pcurr"].value >>> 0)-1;
      else if (n==="pnext") p = (this.elements["pcurr"].value >>> 0)+1;
      else if (n==="plast") p = (this.elements["pcount"].value >>> 0);
      pageNavigate(p);
      return false;
    }
    
    // This would also be handled by a return trip to the server, or else data records could be retrieved via AJAX.
    function pageNavigate(p)
    {
      els1["p"].className = els2["p"].className = els1["p"].value = els2["p"].value = "";
      if (p<1) p = 1; else if (p>NumPages) p = NumPages;
      els1["p1"].disabled = els2["p1"].disabled = els1["pprev"].disabled = els2["pprev"].disabled = (p===1);
      els1["pnext"].disabled = els2["pnext"].disabled = els1["plast"].disabled = els2["plast"].disabled = (p===NumPages);
      els1["pcurr"].value = els2["pcurr"].value = p;
      // if the server is handling this, insert NON-logarithmic page links here (can be just first, current, and last page).
      plinks1.innerHTML = plinks2.innerHTML = logarithmicPaginationLinks(NumPages,p,"?p=");
    }
    
    // This function produces the logarithmic pagination links.
    function logarithmicPaginationLinks(lastPage,matchPage,linkURL)
    {
      function pageLink(p, page) { return ((p===page) ? "<b>"+p+"</b>" : '<a href="'+linkURL+p+'">'+p+"</a>"); }
      function pageGap(x) { if (x===0) return ""; if (x===1) return " "; if (x<=10) return " . "; if (x<=100) return " .. "; return " ... "; }
    
      var page = (matchPage ? matchPage : 1), LINKS_PER_STEP = 5, lastp1 = 1, lastp2 = page, p1 = 1, p2 = page, c1 = LINKS_PER_STEP+1, c2 = LINKS_PER_STEP+1, s1 = "", s2 = "", step = 1, linkHTML = "";
    
      while (true)
      {
        if (c1>=c2)
        {
          s1 += pageGap(p1-lastp1) + pageLink(p1,matchPage);
          lastp1 = p1;
          p1 += step;
          c1--;
        }
        else
        {
          s2 = pageLink(p2,matchPage) + pageGap(lastp2-p2) + s2;
          lastp2 = p2;
          p2 -= step;
          c2--;
        }
        if (c2===0)
        {
          step *= 10;
          p1 += step-1;        // Round UP to nearest multiple of step
          p1 -= (p1 % step);
          p2 -= (p2 % step);   // Round DOWN to nearest multiple of step
          c1 = LINKS_PER_STEP;
          c2 = LINKS_PER_STEP;
        }
        if (p1>p2)
        {
          linkHTML += s1 + pageGap(lastp2-lastp1) + s2;
          if ((lastp2>page)||(page>=lastPage)) break;
          lastp1 = page;
          lastp2 = lastPage;
          p1 = page+1;
          p2 = lastPage;
          c1 = LINKS_PER_STEP;
          c2 = LINKS_PER_STEP+1;
          s1 = '';
          s2 = '';
          step = 1;
        }
      }
      return linkHTML;
    }
    
    window.onload = function()
    {
      els1 = document.getElementById("pager1").elements;
      els2 = document.getElementById("pager2").elements;
      plinks1 = document.getElementById("plinks1");
      plinks2 = document.getElementById("plinks2")
      document.getElementById("pager1").onclick = document.getElementById("pager2").onclick = pageClick;
      (document.getElementById("setupDiv").lastChild.onclick = setupClick)();
    }
    
      </script>
    </head>
    <body>
      <div id="setupDiv">Select number of pages: <input type="text" id="NumPages" value="100" size="7"> &nbsp; &nbsp; and records per page:  <input type="text" id="RecsPerPage" value="20" size="7"> &nbsp; &nbsp; <input type="button" value=" Go "></div>
    
      <hr>
    
      <form id="pager1" class="pager" method="GET"><input type="hidden" name="pcount" value=""><input type="hidden" name="pcurr" value="1">
        <div>Go to page: <input type="text" name="p" size="7"> <input type="submit" value=" Go "></div>
        <div><input type="submit" name="p1" value=" |< " disabled> <input type="submit" name="pprev" value=" < " disabled></div>
        <div id="plinks1" class="plinks"></div>
        <div><input type="submit" name="pnext" value=" > "> <input type="submit" name="plast" value=" >| "></div>
        <div id="plength1"></div>
      </form>
    
      <table id="datarows"><thead><tr><th>Column Heading...</th></tr></thead><tbody></tbody></table>
    
    
      <form id="pager2" class="pager" method="GET"><input type="hidden" name="pcount" value=""><input type="hidden" name="pcurr" value="1">
        <div>Go to page: <input type="text" name="p" size="7"> <input type="submit" value=" Go "></div>
        <div><input type="submit" name="p1" value=" |< " disabled> <input type="submit" name="pprev" value=" < " disabled></div>
        <div id="plinks2" class="plinks"></div>
        <div><input type="submit" name="pnext" value=" > "> <input type="submit" name="plast" value=" >| "></div>
        <div id="plength2"></div>
      </form>
    </body>
    </html>
    
    0 讨论(0)
提交回复
热议问题