You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Golang中借助go-telegram-bot-api实现Telegram内联按钮分页

基于go-telegram-bot-api的内联分页实现

核心逻辑

  • 分页参数(当前页码)存储在内联按钮的callback_data字段中
  • 用户点击按钮触发回调时,解析页码后重新渲染对应页的内容和按钮,更新原有消息即可完成翻页
  • 自动处理边界状态:第一页隐藏「上一页」按钮,最后一页隐藏「下一页」按钮

完整实现示例

首先引入依赖:

import (
    "fmt"
    "strconv"
    "strings"
    tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5"
)

定义分页配置结构体和工具函数:

type PaginationConfig struct {
    CurrentPage int // 当前页码,从1开始
    TotalPages  int // 总页数
    Data        []interface{} // 你的业务数据列表
    PerPage     int // 每页展示条数
}

// 生成分页内联键盘
func generatePaginationKeyboard(pg PaginationConfig) tgbotapi.InlineKeyboardMarkup {
    var row []tgbotapi.InlineKeyboardButton

    // 上一页按钮,当前页大于1才显示
    if pg.CurrentPage > 1 {
        prevBtn := tgbotapi.NewInlineKeyboardButtonData("⬅️ 上一页", fmt.Sprintf("page:%d", pg.CurrentPage-1))
        row = append(row, prevBtn)
    }

    // 页码显示按钮
    pageInfoBtn := tgbotapi.NewInlineKeyboardButtonData(fmt.Sprintf("%d/%d", pg.CurrentPage, pg.TotalPages), "page:noop")
    row = append(row, pageInfoBtn)

    // 下一页按钮,当前页小于总页数才显示
    if pg.CurrentPage < pg.TotalPages {
        nextBtn := tgbotapi.NewInlineKeyboardButtonData("➡️ 下一页", fmt.Sprintf("page:%d", pg.CurrentPage+1))
        row = append(row, nextBtn)
    }

    return tgbotapi.NewInlineKeyboardMarkup(row)
}

// 生成当前页的文本内容,按需修改为你的业务渲染逻辑
func generatePageContent(pg PaginationConfig) string {
    start := (pg.CurrentPage - 1) * pg.PerPage
    end := start + pg.PerPage
    if end > len(pg.Data) {
        end = len(pg.Data)
    }
    currentPageData := pg.Data[start:end]

    var content strings.Builder
    content.WriteString(fmt.Sprintf("📋 数据列表(第%d页,共%d页)\n\n", pg.CurrentPage, pg.TotalPages))
    for i, item := range currentPageData {
        // 这里替换为你自己的数据字段渲染逻辑
        content.WriteString(fmt.Sprintf("%d. %v\n", start+i+1, item))
    }
    return content.String()
}

主逻辑:消息触发+回调处理

func main() {
    // 初始化bot,替换为你的bot token
    bot, err := tgbotapi.NewBotAPI("YOUR_BOT_TOKEN")
    if err != nil {
        panic(err)
    }

    // 示例业务数据,替换为你接口返回的数据
    var allData []interface{}
    for i := 0; i < 100; i++ {
        allData = append(allData, fmt.Sprintf("测试数据项%d", i+1))
    }
    perPage := 10
    totalPages := (len(allData) + perPage - 1) / perPage // 向上取整计算总页数

    u := tgbotapi.NewUpdate(0)
    u.Timeout = 60

    updates := bot.GetUpdatesChan(u)

    for update := range updates {
        // 处理普通消息,触发分页消息发送
        if update.Message != nil && update.Message.Text == "/list" {
            // 初始化第一页
            pg := PaginationConfig{
                CurrentPage: 1,
                TotalPages:  totalPages,
                Data:        allData,
                PerPage:     perPage,
            }
            msg := tgbotapi.NewMessage(update.Message.Chat.ID, generatePageContent(pg))
            msg.ReplyMarkup = generatePaginationKeyboard(pg)
            bot.Send(msg)
            continue
        }

        // 处理分页按钮回调
        if update.CallbackQuery != nil {
            cbData := update.CallbackQuery.Data
            // 只处理分页相关的回调
            if strings.HasPrefix(cbData, "page:") {
                pageStr := strings.TrimPrefix(cbData, "page:")
                // 点击页码展示按钮不做处理
                if pageStr == "noop" {
                    // 应答回调避免加载转圈
                    cbResp := tgbotapi.NewCallback(update.CallbackQuery.ID, "")
                    bot.Send(cbResp)
                    continue
                }

                // 解析页码
                targetPage, err := strconv.Atoi(pageStr)
                if err != nil || targetPage < 1 || targetPage > totalPages {
                    cbResp := tgbotapi.NewCallback(update.CallbackQuery.ID, "页码不合法")
                    bot.Send(cbResp)
                    continue
                }

                // 生成新的分页配置
                pg := PaginationConfig{
                    CurrentPage: targetPage,
                    TotalPages:  totalPages,
                    Data:        allData,
                    PerPage:     perPage,
                }

                // 编辑原有消息,更新内容和按钮
                editMsg := tgbotapi.NewEditMessageText(
                    update.CallbackQuery.Message.Chat.ID,
                    update.CallbackQuery.Message.MessageID,
                    generatePageContent(pg),
                )
                editMsg.ReplyMarkup = &tgbotapi.InlineKeyboardMarkup{
                    InlineKeyboard: generatePaginationKeyboard(pg).InlineKeyboard,
                }
                bot.Send(editMsg)

                // 应答回调
                cbResp := tgbotapi.NewCallback(update.CallbackQuery.ID, "")
                bot.Send(cbResp)
            }
        }
    }
}

注意事项

  • 若你的业务需要支持多用户不同查询条件的分页,可将查询条件、数据列表存入缓存,生成唯一标识放在callback_data中,回调时通过唯一标识取出对应数据即可
  • callback_data字段最大长度为64字节,请勿存入过长内容
  • 必须对回调进行应答,否则用户端按钮会一直显示加载状态

内容的提问来源于stack exchange,提问作者Souriz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 20:06:04