2 votes

Pagination générée de manière procédurale

J'essaie de créer une pagination avec Go mais je suis un peu perdu. C'est la première fois que je crée une pagination car j'avais l'habitude d'utiliser la classe d'aide de Laravel lorsque j'utilisais encore PHP.

J'ai essayé de faire quelque chose comme :

var totalPages = int(math.Ceil(float64(totalRecords) / float64(recordsPerPage)))

for i := 0; i < totalPages; i++ {
    pages[i] = fmt.Sprintf(`<li><a href="?page=%d&limit=%d">%d</a></li>`, i+1, limit, i+1)
}

Et cela montre toutes les pages, je veux créer quelque chose qui ressemblerait à :

< 1 2 ... 20 24 25 26 27 ... 200 201 >

25 étant la page en cours et 201 la dernière page.

J'ai aussi expérimenté quelque chose comme ce qui suit, mais c'était bizarre dans certains cas, par exemple si la page est proche du début ou de la fin :

// pages[0] = fmt.Sprintf(`<li><a href="?page=%d&limit=%d">%d</a></li>`, 1, limit, 1)
// pages[1] = fmt.Sprintf(`<li><a href="?page=%d&limit=%d">%d</a></li>`, 2, limit, 2)
// pages[2] = fmt.Sprintf(`<li><a href="?page=%d&limit=%d">%d</a></li>`, 3, limit, 3)
// pages[3] = `<li><a class="more">&hellip;</a></li>`
// pages[4] = fmt.Sprintf(`<li><a href="?page=%d&limit=%d">%d</a></li>`, page, limit, page)
// pages[5] = fmt.Sprintf(`<li><a href="?page=%d&limit=%d">%d</a></li>`, page+1, limit, page+1)
// pages[6] = fmt.Sprintf(`<li><a href="?page=%d&limit=%d">%d</a></li>`, page+2, limit, page+2)
// pages[7] = fmt.Sprintf(`<li><a href="?page=%d&limit=%d">%d</a></li>`, page+3, limit, page+3)
// pages[8] = fmt.Sprintf(`<li><a href="?page=%d&limit=%d">%d</a></li>`, page+4, limit, page+4)
// pages[9] = fmt.Sprintf(`<li><a href="?page=%d&limit=%d">%d</a></li>`, page+5, limit, page+5)
// pages[10] = fmt.Sprintf(`<li><a href="?page=%d&limit=%d">%d</a></li>`, page+6, limit, page+6)
// pages[11] = `<li><a class="more">&hellip;</a></li>`
// pages[12] = fmt.Sprintf(`<li><a href="?page=%d&limit=%d">%d</a></li>`, totalPages-1, limit, totalPages-1)
// pages[13] = fmt.Sprintf(`<li><a href="?page=%d&limit=%d">%d</a></li>`, totalPages, limit, totalPages)

La question est donc de savoir comment y parvenir. Existe-t-il une bibliothèque ? Quelle est la logique correcte ?

2voto

programaths Points 336

Décomposez votre problème et vous l'obtiendrez.

Ce que vous voulez, c'est calculer les voisins.

package main

import (
    "fmt"
)

func main() {
    pages(8, 2, 13)
}

func pages(n int, around int, count int) {
    first := n - around
    if first < 1 {
        first = 1
    }
    last := n + around
    if last > count {
        last = count
    }

    if first > 1 {
        for i := 1; i <= 2 && i < first; i++ {
            fmt.Println(i)
        }
        if 3 < first {
            fmt.Println("...")
        }
    }

    for i := first; i <= last; i++ {
        fmt.Println(i)
    }

    if last < count {
        if last <= count-3 {
            fmt.Println("...")
        }
        end := count - 1
        if end <= last {
            end = last + 1
        }
        for i := end; i <= count; i++ {
            fmt.Println(i)
        }

    }
}

Amélioration : Rendre variable le nombre de pages "préfixe" et "suffixe" ;-)

Voir : https://play.golang.org/p/wOOO9GmpNV

Ajout d'une version abrégée :

package main

import (
    "fmt"
)

func main() {
    pages(10, 3, 20)
}

func pages(n int, around int, count int) {
    var i int
    for i = 1; i <= 2 && i<=count; i++ {
        fmt.Println(i)
    }

    if i < n-around {
        fmt.Println("...")
        i = n - around
    }

    for ; i <= n+around && i<=count; i++ {
        fmt.Println(i)
    }

    if i < count-1 {
        fmt.Println("...")
        i = count - 1
    }

    for ; i <= count; i++ {
        fmt.Println(i)
    }
}

Nous pouvons facilement envelopper les choses en fournissant un callback. Notez que les canaux sont très lents.

package main

import (
    "fmt"
)

func main() {
    pages(10, 3, 20, func(i int) {
        if i < 0 {
            fmt.Println("...")
            return
        }
        fmt.Println(i)
    })
}

func pages(n int, around int, count int, render func(int)) {
    var i int
    for i = 1; i <= 2 && i <= count; i++ {
        render(i)
    }

    if i < n-around {
        render(-1)
        i = n - around
    }

    for ; i <= n+around && i <= count; i++ {
        render(i)
    }

    if i < count-1 {
        render(-1)
        i = count - 1
    }

    for ; i <= count; i++ {
        render(i)
    }
}

Dernière version (sauf bugs) qui comprend tout :

paquet principal

import (
    "fmt"
)

func main() {
    pages(10, 3, 21,4,4, func(i int) {
        if i < 0 {
            fmt.Println("...")
            return
        }
        fmt.Println(i)
    })
}

func pages(n int, around int, count int,start int, end int, render func(int)) {
    var i int
    for i = 1; i <= start && i <= count; i++ {
        render(i)
    }

    if i < n-around {
        render(-1)
        i = n - around
    }

    for ; i <= n+around && i <= count; i++ {
        render(i)
    }

    if i < count-end+1 {
        render(-1)
        i = count - end+1
    }

    for ; i <= count; i++ {
        render(i)
    }
}

Voir : https://play.golang.org/p/KfTORNuHY_

C'est bon, non ?

  • Ne prend pas plus de mémoire que nécessaire pour les paramètres et la page en cours.
  • Chaque contrôle est effectué une fois.
  • Il suit ce qu'un humain ferait si on lui demandait d'écrire la pagination. (logique naturelle)
  • Le côté appelant ne doit se concentrer que sur le rendu de la page ou du séparateur actuel.
  • Rapide ! Le goulot d'étranglement est le callback.

Notez que si un tableau est nécessaire, on peut le faire par le biais d'une fermeture. De même pour les canaux.

2voto

icza Points 3857

Voici une courte implémentation, qui renvoie les numéros de page que vous devez rendre :

func pages(cur, max, around int) (r []int) {
    for i := cur - around; i <= cur+around; i++ {
        if i >= 1 && i <= max {
            r = append(r, i)
        }
    }
    for i := 1; i <= around; i++ {
        if i < cur-around {
            r = append(r, i)
        }
        if max+1-i > cur+around {
            r = append(r, max+1-i)
        }
    }
    sort.Ints(r)
    return
}

Vous devez passer la page actuelle ( cur ), le numéro de page maximum ( max ), et combien de voisins ( around ) que vous voulez énumérer autour du courant et aux extrémités de la liste

Si deux numéros de page situés l'un à côté de l'autre ont une différence > 1, vous devez également rendre les données suivantes ... entre eux.

Je le teste :

fmt.Println(pages(1, 1, 2))
fmt.Println(pages(1, 2, 2))
fmt.Println(pages(1, 3, 2))
fmt.Println(pages(1, 4, 2))
fmt.Println(pages(1, 5, 2))
fmt.Println(pages(1, 9, 3))
fmt.Println(pages(25, 201, 2))

ps := pages(25, 201, 3)
for i, page := range ps {
    if i > 0 && ps[i-1]+1 < page {
        fmt.Print("... ")
    }
    fmt.Print(page, " ")
}

Sortie (essayez-la sur le Go Playground ):

[1]
[1 2]
[1 2 3]
[1 2 3 4]
[1 2 3 4 5]
[1 2 3 4 7 8 9]
[1 2 23 24 25 26 27 200 201]
1 2 3 ... 22 23 24 25 26 27 28 ... 199 200 201 

Élimination de sort.Ints()

Le but de sort.Ints() est de retourner les numéros de page dans l'ordre croissant. Elle est nécessaire car la deuxième boucle ajoute les numéros dans le désordre.

Si nous pouvons le modifier pour que la deuxième boucle conserve l'ordre, le tri ne sera plus nécessaire.

La deuxième boucle est chargée d'ajouter les numéros de page à partir des extrémités de la liste (début et fin). L'ajout de la fin est correct (il suffit d'aller vers le haut), et nous ajouterons le début à une autre tranche, à laquelle le reste sera ajouté.

C'est ici :

func pages(cur, max, around int) (r []int) {
    for i := cur - around; i <= cur+around; i++ {
        if i >= 1 && i <= max {
            r = append(r, i)
        }
    }
    r2 := make([]int, 0, len(r)+4)
    for i := 1; i <= around; i++ {
        if i < cur-around {
            r2 = append(r2, i)
        }
        if max-around+i > cur+around {
            r = append(r, max-around+i)
        }
    }
    return append(r2, r...)
}

Les tests et les résultats sont les mêmes. Essayez cette variante de la Go Playground .

Spécifier également le nombre de pages aux extrémités

Si vous voulez un nombre différent de pages aux extrémités, vous pouvez ajouter 1 paramètre supplémentaire et l'utiliser avec 0 complexité ajoutée :

func pages(cur, max, around, edge int) (r []int) {
    for i := cur - around; i <= cur+around; i++ {
        if i >= 1 && i <= max {
            r = append(r, i)
        }
    }
    r2 := make([]int, 0, len(r)+2*edge)
    for i := 1; i <= edge; i++ {
        if i < cur-around {
            r2 = append(r2, i)
        }
        if max-around+i > cur+around {
            r = append(r, max-around+i)
        }
    }
    return append(r2, r...)
}

Essayez cette variante de la Go Playground .

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X