
本文介绍如何在 Go 中实现类似 的智能分页逻辑,支持当前页居中、首尾固定显示、动态省略号插入,无需第三方库,代码轻量、高效且可扩展。
本文介绍如何在 go 中实现类似 `` 的智能分页逻辑,支持当前页居中、首尾固定显示、动态省略号插入,无需第三方库,代码轻量、高效且可扩展。
在 Web 开发中,分页不仅是功能需求,更是用户体验的关键一环。简单列出全部页码(如 1 2 3 ... 200)在数据量大时既低效又难读;而硬编码固定偏移(如“始终显示前后 3 页”)又会在边界页(第 1 页、最后几页)导致逻辑断裂或重复渲染。理想的分页应具备以下特性:
- ✅ 当前页始终可见并居中突出
- ✅ 首部固定显示前
N页(如1 2) - ✅ 尾部固定显示后
M页(如200 201) - ✅ 中间长间隔自动替换为
...(仅当真实省略发生时) - ✅ 时间/空间复杂度为 O(1) —— 仅遍历需渲染的页码,不预分配大数组
下面是一个生产就绪的 Go 分页生成器,采用回调驱动(callback-based)设计,解耦页码计算与 HTML 渲染:
// pages renders pagination items via callback: negative i means ellipsis
func pages(current, around, total, prefix, suffix int, render func(i int)) {
var i int
// Render prefix: e.g., "1 2"
for i = 1; i <= prefix && i <= total; i++ {
render(i)
}
// Insert leading ellipsis if gap exists before centered block
if i < current-around {
render(-1) // signal ellipsis
i = current - around
}
// Render centered block: [current−around, current+around]
for ; i <= current+around && i <= total; i++ {
render(i)
}
// Insert trailing ellipsis if gap exists before suffix
if i < total-suffix+1 {
render(-1)
i = total - suffix + 1
}
// Render suffix: e.g., "200 201"
for ; i <= total; i++ {
render(i)
}
}使用示例(生成 HTML 片段):
var html []string
pages(25, 3, 201, 2, 2, func(i int) {
switch {
case i == -1:
html = append(html, `<li class="ellipsis"><span>…</span></li>`)
case i == 25:
html = append(html, fmt.Sprintf(`<li class="active"><span>%d</span></li>`, i))
default:
html = append(html, fmt.Sprintf(`<li><a href="?page=%d&limit=10">%d</a></li>`, i, i))
}
})
fmt.Println(strings.Join(html, "\n"))输出效果(节选):
<li><a href="?page=1&limit=10">1</a></li> <li><a href="?page=2&limit=10">2</a></li> <li class="ellipsis"><span>…</span></li> <li><a href="?page=22&limit=10">22</a></li> <li><a href="?page=23&limit=10">23</a></li> <li><a href="?page=24&limit=10">24</a></li> <li class="active"><span>25</span></li> <li><a href="?page=26&limit=10">26</a></li> <li><a href="?page=27&limit=10">27</a></li> <li class="ellipsis"><span>…</span></li> <li><a href="?page=200&limit=10">200</a></li> <li><a href="?page=201&limit=10">201</a></li>
? 关键设计说明:
-
around控制以当前页为中心的左右扩展数(默认 ±3 → 共 7 个连续页); -
prefix/suffix独立控制首尾固定显示页数(推荐2,兼顾简洁与导航性); -
render(-1)是约定信号,由调用方决定如何渲染省略号(支持 CSS 类、SVG 或无障碍标记); - 无内存泄漏风险:不预分配切片,不缓存中间结果,适合高并发模板渲染场景;
- 可无缝集成 Gin / Echo / Fiber 等框架:将
render替换为c.HTML()或模板变量注入。
⚠️ 注意事项:
-
current必须已校验为1 ≤ current ≤ total,建议前置做参数归一化(如current = clamp(current, 1, totalPages)); - 若需支持「上一页/下一页」按钮,应在
pages()外围手动拼接; - 对 SEO 友好:确保所有
<a></a>标签含有效href,禁用 JavaScript 时仍可跳转; - 如需国际化(如多语言省略号),将
"..."提取为配置项或本地化函数。
该方案摒弃了 Laravel 风格的“全量生成再裁剪”,转而采用流式构造(streaming construction)——每一步只决策“下一个该输出什么”,逻辑清晰、边界鲁棒、性能恒定,是 Go 生态中符合惯用法(idiomatic Go)的分页实践范本。

















