pagedlistadapter livedata library example user-interface navigation pagination paging large-data-volumes

user-interface - livedata - pagedlistadapter



¿Cómo hacer la navegación de páginas para muchas, muchas páginas? Navegación logarítmica de páginas (4)

Versión simplificada de "Navegación logarítmica de página" en JavaScript:

Genera el menú desplegable. Este ejemplo solo lo documenta.write, pero puede desarrollarlo según sus necesidades (agregue onChange, etc.). Conversión de Javascript gracias a 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>

¿Cuál es la mejor manera de mostrar la navegación de la página para muchas, muchas páginas?

(Inicialmente, esto se publicó como una sugerencia de procedimientos con mi respuesta incluida en la pregunta. Ahora he dividido mi respuesta en la sección de "respuestas" a continuación).

Para ser más especifico:

Supongamos que está mostrando un conjunto de registros al usuario, divididos en páginas de tamaño fijo (como los resultados de una búsqueda de Google, por ejemplo). Si solo hay unas pocas páginas, puede mostrar un área de navegación de página al final de los resultados que podría verse así:

[<<] [<] 1 2 3 4 5 6 7 8 9 10 11 12 13 [>] [>>]

Pero esto rápidamente se vuelve inverosímil si hay más de 20 o 30 páginas de resultados.

A veces verás cosas como esta:

[<<] [<] ... 665 666 667 668 669 670 671 672 673 ... [>] [>>]

o esto:

[<<] [<] 1 2 3 ... 667 668 669 670 671 ... 845 846 847 [>] [>>]

pero en ambos casos, navegar a cualquier parte en medio de las secciones "..." llevaría muchos, muchos clics de ratón. A veces se proporciona un cuadro de entrada para ingresar el número de página directamente; de lo contrario (suponiendo que estemos hablando de una página web aquí) es probable que el usuario inteligente vea la URL para ver si puede editarla directamente.

Lo que sería bueno sería tener una pantalla de paginación que le permita al usuario llegar a cualquier página en solo unos pocos clics del mouse, sin tener ridículamente muchos enlaces.

¿Cómo se lograría eso mejor?


Aquí está mi solución - use "Navegación de página logarítmica":

Esto se puede lograr al tener los números de página distribuidos logarítmicamente, de acuerdo con la distancia desde los puntos finales o la página actual. Aquí hay un ejemplo de lo que quiero decir:

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

Observe cómo en las brechas, la numeración va de 1s, a 10s, a 100s (etc.). (Yo uso potencias de 10, pero en principio podrías usar un esquema diferente, potencias de 2, por ejemplo).

Escribí un código que hace esto en 2004 y pensé que lo compartiría aquí. Existen versiones de PHP y ASP, pero la lógica debería ser fácil de traducir a cualquier idioma. Tenga en cuenta que el bit en la parte inferior (en ambos casos) solo muestra algunos ejemplos. Obviamente, el formato necesitará personalización para que coincida con su página web (o aplicación), por lo que es bastante básico aquí. LINKS_PER_STEP en paginationHTML para determinar cuántos números se muestran antes de que aumente el tamaño del paso, a medida que se aleja de los puntos finales o de la página actual.

Para una salida más compacta, también podría considerar alterar el código para que la numeración no sea "densa" alrededor de los puntos finales (es decir, densa solo alrededor de la página actual).

Aquí está el código:

Versión de PHP:

<? // 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='')?>

Versión ASP:

<% '' 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=")%>

Versión de Javascript (dentro de la página de prueba completa):

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


Pienso en dos alternativas de paginación logarítmica:

  1. Si es relevante, podría dividir sus datos en secciones, capítulos y libros. Esta es la forma antigua, cuando el papel era el rey, y las bibliotecas hicieron el trabajo de internet. Algunos documentos PDF todavía tienen eso.

  2. Puede ofrecer un cuadro de búsqueda, como Wikipedia, si alguien quiere saltar a la parte de big data donde se menciona el supercalifragilisticexpialidocious .


Qué tal si:

a) agregue <-100 <-10 [paginación] +10> +100> en lugar de inflar la paginación en sí

b) ofrezca una entrada de página directa [# ..] [ver], filtre la entrada contra el rango de páginas válido

c) necesita una codificación adecuada, pero: ampliar el rango flotante interno, por ejemplo, +/- 10, +/- 25, +/- 100 páginas en lugar de ampliar el rango completo de paginación