如何用Hikari/Lightbulb实现长Embed消息分页及按钮翻页?
实现Hikari-Lightbulb分页Embed与按钮切换
实现步骤与代码
1. 前置准备
确保已安装hikari和hikari-lightbulb依赖,机器人已开启组件交互权限。
2. 完整代码实现
import hikari import lightbulb from lightbulb import plugin plugin = plugin.Plugin("FruitPagination") # 每页显示条目数,可根据Discord Embed字段上限(25个)调整 PER_PAGE = 10 @plugin.command @lightbulb.option('type', 'fruit type', modifier=lightbulb.OptionModifier.CONSUME_REST) @lightbulb.command('fruit', 'available fruit') @lightbulb.implements(lightbulb.SlashCommand) async def lan(ctx: lightbulb.Context) -> None: if ctx.options.type != 'fru': await ctx.respond("仅支持查询'fru'类型的水果") return # 读取文件内容,自动关闭文件 loglist = [] try: with open("fru.txt", "r", encoding="utf8") as file: for line in file.readlines(): line = line.strip() if line: # 跳过空行 loglist.append(line) except FileNotFoundError: await ctx.respond("未找到fru.txt文件") return if not loglist: await ctx.respond("当前没有可显示的水果数据") return # 拆分内容为分页 pages = [loglist[i:i+PER_PAGE] for i in range(0, len(loglist), PER_PAGE)] total_pages = len(pages) # 生成指定页码的Embed def get_page_embed(page_num: int) -> hikari.Embed: embed = hikari.Embed(title=f"Fruits - 第 {page_num+1}/{total_pages} 页", description="--------------------") for item in pages[page_num]: embed.add_field(name="-----", value=f"`{item}`", inline=False) return embed # 生成指定页码的控制按钮 def get_page_buttons(page_num: int) -> list[hikari.api.MessageActionRowBuilder]: prev_disabled = page_num == 0 next_disabled = page_num == total_pages - 1 prev_btn = hikari.Button( style=hikari.ButtonStyle.PRIMARY, label="上一页", custom_id=f"fruit_prev_{ctx.user.id}_{page_num}", is_disabled=prev_disabled ) next_btn = hikari.Button( style=hikari.ButtonStyle.PRIMARY, label="下一页", custom_id=f"fruit_next_{ctx.user.id}_{page_num}", is_disabled=next_disabled ) return [hikari.MessageActionRowBuilder().add_button(prev_btn).add_button(next_btn)] # 发送初始分页消息 await ctx.respond(embed=get_page_embed(0), components=get_page_buttons(0)) # 监听按钮交互事件 @plugin.listener(hikari.InteractionCreateEvent) async def on_button_click(event: hikari.InteractionCreateEvent) -> None: # 仅处理组件按钮交互 if not isinstance(event.interaction, hikari.ComponentInteraction): return interaction = event.interaction custom_id = interaction.custom_id # 过滤非水果分页的按钮 if not custom_id.startswith("fruit_"): return # 解析自定义ID中的参数:操作类型、用户ID、当前页码 parts = custom_id.split("_") if len(parts) != 4: return action, user_id_str, current_page_str = parts[1], parts[2], parts[3] try: user_id = int(user_id_str) current_page = int(current_page_str) except ValueError: return # 仅允许触发命令的用户操作按钮 if interaction.user.id != user_id: await interaction.create_response( hikari.ResponseType.MESSAGE_CREATE, content="你无权操作此分页按钮", flags=hikari.MessageFlag.EPHEMERAL ) return # 重新读取数据(如需优化可缓存数据) loglist = [] with open("fru.txt", "r", encoding="utf8") as file: for line in file.readlines(): line = line.strip() if line: loglist.append(line) pages = [loglist[i:i+PER_PAGE] for i in range(0, len(loglist), PER_PAGE)] total_pages = len(pages) # 计算新页码 new_page = current_page if action == "prev" and current_page > 0: new_page -= 1 elif action == "next" and current_page < total_pages - 1: new_page += 1 else: await interaction.create_response(hikari.ResponseType.DEFERRED_MESSAGE_UPDATE) return # 生成新页面的Embed和按钮 new_embed = hikari.Embed(title=f"Fruits - 第 {new_page+1}/{total_pages} 页", description="--------------------") for item in pages[new_page]: new_embed.add_field(name="-----", value=f"`{item}`", inline=False) new_prev_disabled = new_page == 0 new_next_disabled = new_page == total_pages - 1 new_prev_btn = hikari.Button( style=hikari.ButtonStyle.PRIMARY, label="上一页", custom_id=f"fruit_prev_{user_id}_{new_page}", is_disabled=new_prev_disabled ) new_next_btn = hikari.Button( style=hikari.ButtonStyle.PRIMARY, label="下一页", custom_id=f"fruit_next_{user_id}_{new_page}", is_disabled=new_next_disabled ) new_components = [hikari.MessageActionRowBuilder().add_button(new_prev_btn).add_button(new_next_btn)] # 更新分页消息 await interaction.edit_response(embed=new_embed, components=new_components) # 注册插件 def load(bot: lightbulb.BotApp) -> None: bot.add_plugin(plugin)
关键说明
- 分页逻辑:通过列表切片将内容按指定数量拆分页面,适配Discord Embed的字段限制。
- 权限控制:自定义ID携带用户ID,确保只有触发命令的用户能操作对应分页,避免跨用户误操作。
- 组件更新:点击按钮后通过
edit_response更新消息内容,实现无刷新分页切换。 - 异常处理:包含文件不存在、空数据等场景的处理,提升机器人稳定性。
内容的提问来源于stack exchange,提问作者Name
相关产品推荐
相关产品推荐

