php - simple - paginacion y segmentacion
Lógica detrás de la paginación como google (7)
¡Esta conversación fue un gran comienzo para mí! Pero quería un paginador más cercano a las intenciones de la pregunta original, que:
1) Podría estar contenido en una función con variables para alterar el total de páginas, la página actual y el número de páginas en cada lado de la corriente para mostrar.
2) Mantiene un ancho constante, similar al original:
< [1] 2 3 4 5 6 7 ... 99 >
< 1 [2] 3 4 5 6 7 ... 99 >
< 1 2 [3] 4 5 6 7 ... 99 >
< 1 2 3 [4] 5 6 7 ... 99 >
< 1 2 3 4 [5] 6 7 ... 99 >
< 1 ... 4 5 [6] 7 8 ... 99 >
< 1 ... 5 6 [7] 8 9 ... 99 >
< 1 ... 92 93 [94] 95 96 ... 99 >
< 1 ... 93 94 [95] 96 97 98 99 >
< 1 ... 93 94 95 [96] 97 98 99 >
< 1 ... 93 94 95 96 [97] 98 99 >
< 1 ... 93 94 95 96 97 [98] 99 >
< 1 ... 93 94 95 96 97 98 [99] >
3) Continúa mostrando el número "2" en lugar de "..." en los casos en que tendría 1 ... 3
4) Lo mismo para el final.
Así que aquí está lo que hice. Estoy codificando en un idioma diferente (coffeescript), pero debería funcionar como un buen sudo-code de todos modos:
get_pages_array = (total_page, each_side, curr_page) ->
if total_page <= (2*each_side)+5
# in this case, too few pages, so display them all
start_page = 1
end_page = total_page
else if curr_page<=each_side+3
# in this case, curr_page is too close to the beginning
start_page = 1
end_page = (2*each_side)+3
else if curr_page >= total_page - (each_side+2)
# in this case, curr_page is too close to the end
start_page = total_page - (2*each_side) - 2
end_page = total_page
else
# regular case
start_page = curr_page - each_side
end_page = curr_page + each_side
return_me = []
if start_page> 1
return_me.push "1"
if start_page>2
return_me.push "..."
for x in [start_page..end_page]
return_me.push x
if end_page<total_page-1
return_me.push "..."
if end_page<total_page
return_me.push total_page
return return_me
Estoy usando este código para each_side = 2, así que ahí es donde estoy seguro de que funciona.
EDITAR: lógica fija según @Vextil
¿Cuál es la lógica detrás del comportamiento de paginación de google?
Mi paginador va algo como esto:
[1] 2 3 ... 184 >
< 1 [2] 3 4 ... 184 >
< 1 2 [3] 4 5 ... 184 >
< 1 2 3 [4] 5 6 ... 184 >
< 1 ... 3 4 [5] 6 7 ... 184 >
< 1 ... 4 5 [6] 7 8 ... 184 >
< 1 ... 5 6 [7] 8 9 ... 184 >
< 1 ... 6 7 [8] 9 10 ... 184 >
Aquí hay una versión en vivo del ejemplo anterior: http://www.dev.thomaskile.me/?page=test-zone&module=Paginator .
Sé por qué sucede esto; He establecido la cantidad de números de página que se mostrarán en cada lado de la página actual en dos (2).
Preferiría tener el rango de números para ser igual a esto:
[1] 2 3 4 5 6 7 8 ... 184 >
< 1 [2] 3 4 5 6 7 ... 184 >
< 1 2 [3] 4 5 6 7 ... 184 >
< 1 2 3 [4] 5 6 7 ... 184 >
< 1 ... 3 4 [5] 6 7 ... 184 >
< 1 ... 4 5 [6] 7 8 ... 184 >
< 1 ... 5 6 [7] 8 9 ... 184 >
< 1 ... 6 7 [8] 9 10 ... 184 >
Es al principio y al final, necesito hacer algunos cambios, pero no puedo descubrir cómo hacer que sea una operación fácil ...
También me gustaría hacerlo flexible. Lo que significa que me gustaría poder cambiar el número de páginas deseadas en cada lado y hacer que el script se expanda y calcule todo ...
Aquí está mi código hasta ahora:
/**
* page controller buttons
* @param str $this->querySting href="URL string"
* @param str $this->pageIdentifier $_GET[''this-name'']
* @param int $this->numPages Total amount of pages
* @param int $this->midRange Number of pages to show on each side of current page
*/
public function prevPage()
{
if ($this->currentPage > 1){
$prevPage = ($this->currentPage - 1);
return ''<a href="''.$this->queryString.''&''.$this->pageIdentifier.''=''.$prevPage.''" class="prev">prev</a>'';
}
}
public function nextPage()
{
if ($this->currentPage < $this->numPages) {
$nextPage = $this->currentPage + 1;
return ''<a href="''.$this->queryString.''&''.$this->pageIdentifier.''=''.$nextPage.''" class="next">next</a>'';
}
}
public function firstPage()
{
if ($this->currentPage > ($this->midRange + 1)) { // if number of pages between "currentPage" and "firstPage" exceeds $midRange with 1...
$firstPage .= ''<a href="''.$this->queryString.''&''.$this->pageIdentifier.''=1" class="first">1</a>''; // ...show "first page"-link
if ($this->currentPage > ($this->midRange + 2)) { // if number of pages between $currentPage and "first page" exceeds $midRange with more than 1
$firstPage .= ''…''; // add "..." between "1st page"-link and first page in $range
}
}
return $firstPage;
}
public function lastPage()
{
if ($this->currentPage < ($this->numPages - $this->midRange)) { // if number of pages between "currentPage" and "last page" is equal to $midRange
if (($this->currentPage < ($this->numPages - $this->midRange) - 1)) { // if number of pages between $currentPage and "last page" exceeds $range with more than two
$lastPage .= ''…''; // add "..." between "last page"-link and last page in $range
}
$lastPage .= ''<a href="''.$this->queryString.''&''.$this->pageIdentifier.''=''.$this->numPages.''" class="last">''.$this->numPages.''</a>''; // show "last page"-link
}
return $lastPage;
}
# Range of pages between (prev first ...) and (... last next)
public function listPages()
{
for ($i = ($this->currentPage - $this->midRange); $i < (($this->currentPage + $this->midRange) + 1); $i++){
if (($i > 0) && ($i <= $this->numPages)) // if page number are within page range
{
if ($i == $this->currentPage) { $listPages .= ''<a class="current">''.$i.''</a>''; } // if we''re on current page
else { $listPages .= ''<a href="''.$this->queryString.''&''.$this->pageIdentifier.''=''.$i.''">''.$i.''</a>''; } // if not current page
}
}
return $listPages;
}
Aquí hay un programa de Python que muestra cómo hacer esto correctamente:
def main():
num_pages = 13
page = 12
window = 5
start = page - window
end = page + window - 1
if start <= 0:
end = end - start + 1
start = 1
if end > num_pages:
end = num_pages
start = max(end - (window * 2) + 1, 1)
for no in range(start, end + 1):
print "{}*".format(no) if page == no else no
if __name__ == ''__main__'':
main()
Escuchar es un ejemplo simple de visualización de paginación:
$paginationDisplay = ""; // Initialize the pagination output variable
// This code runs only if the last page variable is not equal to 1,
// if it is only 1 page we require no paginated links to display
if ($lastPage != "1"){
// This shows the user what page they are on, and the total number of pages
$paginationDisplay .= ''Page <strong>'' . $pn .
''</strong> of '' . $lastPage. ''last'';
// If we are not on page 1 we can place the Back button
if ($pn != 1) {
$previous = $pn - 1;
$paginationDisplay .= '' <a href="'' .
$_SERVER[''PHP_SELF''] . ''?pn='' . $previous . ''"> Back</a> '';
}
// Lay in the clickable numbers display here between the Back and Next links
$paginationDisplay .= ''<span>'' . $centerPages . ''</span>'';
// If we are not on the very last page we can place the Next button
if ($pn != $lastPage) {
$nextPage = $pn + 1;
$paginationDisplay .= '' <a href="'' .
$_SERVER[''PHP_SELF''] . ''?pn='' . $nextPage . ''"> Next</a> '';
}
}
Esta es la lógica de paginación que tengo
$pLinks = 5; // Links per page
$pMids = 3;
$pTot = 10; // Total page
$pSel = 1 // Selected page
if (($pSel <= $pMids) || ($pTot <= $pLinks)) {
$sPage = 1;
$ePage = ($pTot <= $pLinks) ? $pTot : $pLinks;
} else {
$etPage = $pSel + ($pMids - 1);
$ePage = ($etPage <= $pTot) ? $etPage : $pTot;
$sPage = $ePage - ($pLinks - 1);
}
if ($pSel > $sPage) {
$sL = ''<a href="#" id="1">First</a>'';
$sN = ''<a href="#" id="''.($pSel-1).''">«</a>'';
} else {
$sL = ''First'';
$sN = ''«'';
}
if ($pSel < $ePage) {
$eL = ''<a href="#" id="''.$pTot.''">End</a>'';
$eN = ''<a href="#" id="''.($pSel+1).''">»</a>'';
} else {
$eL = ''End'';
$eN = ''»'';
}
$pOptions = '''';
$pOptions .= ''<span class="iPage">''.$pSel.''/''.$pTot.''</span>'';
$pOptions .= ''<span class="renderFL">''.$sL.''</span>'';
$pOptions .= ''<span class="renderPN">''.$sN.''</span>'';
for ($i = $sPage; $i <= $ePage; $i++) {
if($i != $pSel) {
$pOptions .= ''<span><a href="#" id="''.$i.''">''.$i.''</a></span>'';
} else {
$pOptions .= ''<span class="selected">''.$i.''</span>'';
}
}
$pOptions .= ''<span class="renderPN">''.$eN.''</span>'';
$pOptions .= ''<span class="renderFL">''.$eL.''</span>'';
El resultado se vería así:
1 -> [1] 2 3 4 5
2 -> 1 [2] 3 4 5
3 -> 1 2 [3] 4 5
..
5 -> 3 4 [5] 6 7
6 -> 4 5 [6] 7 8
..
8 -> 6 7 [8] 9 10
9 -> 6 7 8 [9] 10
10 -> 6 7 8 9 [10]
Esto es lo que hago para mi Paginación.
$startPage = $currentPage - 4;
$endPage = $currentPage + 4;
if ($startPage <= 0) {
$endPage -= ($startPage - 1);
$startPage = 1;
}
if ($endPage > $totalPage)
$endPage = $totalPage;
if ($startPage > 1) echo " First ... ";
for($i=$startPage; $i<=$endPage; $i++) echo " {$i} ";
if ($endPage < $totalPage) echo " ... Last ";
Creo que mi código se explica por sí mismo, pero intentaré explicarlo en un lenguaje sencillo. En primer lugar, necesita saber dos cosas antes de poder generar Paginación: $ totalPage y $ currentPage .
Paso 1 : Suponiendo que la página actual está en el rango medio. $ startPage y $ endPage almacenan el rango de página que la paginación intenta generar.
Paso 2 : Si $ startPage es negativo, entonces necesitas recuperar $ endPage .
Paso 3 : Si $ endPage en exceso de $ totalPage , entonces $ endPage es la última página.
Paso 4 : Generación de paginación en HTML. (Depende de usted cómo desea que se vea su paginación. Simplemente usaré texto sin formato para representar mi paginación)
if ($startPage > 1) echo " First ... ";
for($i=$startPage; $i<=$endPage; $i++) echo " {$i} ";
if ($endPage < $totalPage) echo " ... Last ";
Fallo corregido a mi lógica anterior
$startPage = ($curPage < 5)? 1 : $curPage - 4;
$endPage = 8 + $startPage;
$endPage = ($totalPage < $endPage) ? $totalPage : $endPage;
$diff = $startPage - $endPage + 8;
$startPage -= ($startPage - $diff > 0) ? $diff : 0;
if ($startPage > 1) echo " First ... ";
for($i=$startPage; $i<=$endPage; $i++) echo " {$i} ";
if ($endPage < $totalPage) echo " ... Last ";
Supongo que su paginación tiene esta estructura:
número_de_página_activa + separada (...) + página (184) + página_actual (>)
Puede configurar number_of_active_page convertido en 8 (incluya prev_page (<) + páginas (... y número de página)
[1] 2 3 4 5 6 7 8 ... 184 >
[number_of_active_page(set to 8)] + separate + page + next_page
< 1 ... 3 4 [5] 6 7 ... 184 >
¡Esto es puro asombroso! Creo que conseguí que este paginador funcionara como lo describí.
Por favor, eche un vistazo y pruébelo aquí dev.thomaskile.me/?page=test-zone&module=Paginator y hágamelo saber ...
Después de mucho estudio de matemáticas lógicas, finalmente llegué a esta conclusión:
Para hacer que este acto sea tan diferente en diferentes niveles, tiene que haber algunos if
, elsef
-s para manejar la lógica en cada nivel por separado. Intentaré explicarlo, pero me resulta difícil hacerlo de buena manera ...
Estos son los niveles de los que estoy hablando:
Si currentPage == firstPage:
Calcule cuántas páginas se mostrarán después de currentPage a partir de la segunda página.
Este cálculo debía realizarse en función del número de cuadros de página que hubiera como máximo. (El valor de rango medio es un factor clave aquí)[1] 2 3 4 5 6 7 8 ... 184 >
elseif currentPage está entre firstPage y midRange el valor máximo.
Reduzca las páginas dentro del rango en uno para evitar mover todo el paginador a la derecha una vez que se agrega prevPage. Calcule páginas para mostrar antes y después de currentPage para mantener la cantidad de páginas igual a todo.< 1 [2] 3 4 5 6 7 ... 184 > < 1 2 [3] 4 5 6 7 ... 184 > < 1 2 3 [4] 5 6 7 ... 184 >
El valor de rango medio de elseif está al máximo en cada lado. Lo que significa que estamos en el medio en algún lugar.
midRange pages + la página actual + midRange pages. Bastante sencillo, supongo ...< 1 ... 3 4 [5] 6 7 ... 184 > ... ... ... < 1 ... 178 179 [180] 181 182 ... 184 >
elseif currentPage está entre el valor de midRange y lastPage
Casi lo mismo que en el principio. La diferencia era calcular un número de página estático para comenzar las páginas, luego calcular las páginas para mostrar antes / después de la página actual ...
(Esto, por cierto, ha sido mi dolor de cabeza este fin de semana)< 1 ... 178 179 180 [181] 182 183 184 > < 1 ... 178 179 180 181 [182] 183 184 > < 1 ... 178 179 180 181 182 [183] 184 >
elseif currentPage == numPages (número de páginas tatal). Más o menos lo mismo que la operación de primera página ... calculando cuántas páginas se necesitan para completar todo y calcular dónde comenzar ...
Lo que necesito hacer ahora es hacer que el código sea mejor ...
< 1 ... 178 179 180 181 182 183 [184] >
El "problema" en mi caso era que todo el paginador debería calcular todo en función del valor de rango medio y nada más. Para ejecutar este paginador en cualquiera de mis proyectos futuros, todo lo que tengo que hacer es:
$paginator = new paginator((int)); // e.g. number of total results from a db request
Es posible que en la mayoría de los casos tenga que agregar una cadena de consulta personal para asegurarme de que funciona a href
:
$paginator->set_queryString(''my querystring'');
Y eso es prácticamente todo. He configurado un par de funciones opcionales como esta:
$paginator->set_resultsPerPage((int));
$paginator->set_midRange((int));
$paginator->set_pageIdentifier(''querystring-pageNumber-identifier-name-for-get''); // whatever I needed
Finalmente muestro el controlador de la página del paginador de esta manera:
$paginator->pageController(''full''); // full, med, min for different styles.
Si ninguno de estos es lo suficientemente bueno, podría llamar a cada botón así:
$paginator->prevPage();
$paginator->firstPage();
$paginator->listPages();
$paginator->lastPage();
$paginator->nextPage();
$paginator->pageJumper();
$paginator->perPageSelector();