douwen4125 2017-02-07 15:34
浏览 31
已采纳

程序生成分页

I'm trying to create pagination with Go but I'm a bit confused. It's my first time to creating pagination as I used to use laravel's helper class when I was still using PHP.

I tried doing something like:

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)
}

And that shows all the pages, I want to create something that would look like:

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

25 being current page and 201 being the last page.

I also experimented with something like the following but was quirky on some cases like if the page is close to the start or the end:

// 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)

So the question is, how do I achieve this? Is there a library? What is the correct logic?

  • 写回答

2条回答 默认 最新

  • douhui7136 2017-02-07 15:58
    关注

    Break down your problem and you will get it.

    What you want is to compute the neighbors.

    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)
            }
    
        }
    }
    

    Improvement : Make number of "prefix" and "suffix" pages variable ;-)

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

    Added a shortened version :

    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)
        }
    }
    

    We can easily wrap things around by providing a callback. Note that channels are very slow.

    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)
        }
    }
    

    Last version (unless bugs) which includes everything :

    package main

    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)
        }
    }
    

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

    How good is this ?

    • Take no more memory than required for parameters and current page.
    • Each check is done once.
    • It follows what a human would do if asked to write down pagination. (natural logic)
    • Caller side only has to focus on rendering of current page or separator.
    • Fast ! The bottleneck is the callback.

    Note, if an array is needed, one can do it through a closure. Same with channels.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 微信会员卡接入微信支付商户号收款
  • ¥15 如何获取烟草零售终端数据
  • ¥15 数学建模招标中位数问题
  • ¥15 phython路径名过长报错 不知道什么问题
  • ¥15 深度学习中模型转换该怎么实现
  • ¥15 HLs设计手写数字识别程序编译通不过
  • ¥15 Stata外部命令安装问题求帮助!
  • ¥15 从键盘随机输入A-H中的一串字符串,用七段数码管方法进行绘制。提交代码及运行截图。
  • ¥15 TYPCE母转母,插入认方向
  • ¥15 如何用python向钉钉机器人发送可以放大的图片?