discord.js命令处理器下为embed分页添加按钮交互的实现方法
实现方案
核心使用discord.js内置的组件收集器实现在单个命令文件内处理按钮交互,无需修改命令处理器的入口文件,同时解决await报错问题。
你遇到的await报错是因为你定义的cinfo是普通同步函数,await关键字仅可在被async标记的函数内使用,将cinfo改为async函数即可解决。
修改后的完整代码
const { SlashCommandBuilder } = require("@discordjs/builders"); const Discord = require("discord.js"); const info = require("./info.json"); module.exports = { data: new SlashCommandBuilder() .setName("cinfo") .setDescription("Shows AniGame card info") .addStringOption(option => option .setName("name") .setDescription("Enter the name of a card") .setRequired(true) // 建议改为必填,避免空值报错 ), async execute(interaction) { const msg = interaction.options.getString("name").toLowerCase(); // 将cinfo改为async函数以支持await async function cinfo( name, info, stats, talent, image, sr1, sr2, sr3, srt, ur1, ur2, ur3, urt ) { const base = new Discord.MessageEmbed() .setTitle(name) .setColor(0xffd1dc) .setDescription(info) .addField("__Card Stats__", stats) .addField("Talent", talent) .setImage(image); const sr = new Discord.MessageEmbed() .setTitle(name + " | Level 50") .setColor(0xffd1dc) .addField("__SR Evo 1__", sr1, true) .addField("__SR Evo 2__", sr2, true) .addField("__SR Evo 3__", sr3, true) .addField("Talent", srt) .setImage(image); const ur = new Discord.MessageEmbed() .setTitle(name + " | Level 60") .setColor(0xffd1dc) .addField("__UR Evo 1__", ur1, true) .addField("__UR Evo 2__", ur2, true) .addField("__UR Evo 3__", ur3, true) .addField("Talent", urt) .setImage(image); const row = new Discord.MessageActionRow().addComponents( new Discord.MessageButton() .setCustomId("backward") .setStyle("PRIMARY") .setEmoji("⬅️"), new Discord.MessageButton() .setCustomId("forward") .setStyle("PRIMARY") .setEmoji("➡️"), new Discord.MessageButton() .setCustomId("delete") .setStyle("DANGER") .setEmoji("🗑️") ); const pages = [base, sr, ur]; let currentIndex = 0; // 记录当前分页索引 // 等待回复发送完成,获取回复消息对象 const reply = await interaction.reply({ embeds: [pages[currentIndex]], components: [row], fetchReply: true }); // 定义过滤器:仅允许发起命令的用户操作按钮 const filter = i => i.user.id === interaction.user.id; // 创建组件收集器,超时时间设为5分钟,单位为毫秒 const collector = reply.createMessageComponentCollector({ filter, time: 300000 }); // 监听按钮点击事件 collector.on("collect", async i => { if (i.customId === "forward") { // 前进按钮:索引+1,超过数组长度则回到0 currentIndex = currentIndex + 1 >= pages.length ? 0 : currentIndex + 1; } else if (i.customId === "backward") { // 后退按钮:索引-1,小于0则跳到最后一页 currentIndex = currentIndex - 1 < 0 ? pages.length - 1 : currentIndex - 1; } else if (i.customId === "delete") { // 删除按钮:直接删除回复 await reply.delete(); return; } // 更新消息的嵌入内容 await i.update({ embeds: [pages[currentIndex]], components: [row] }); }); // 监听收集器结束事件:超时后禁用所有按钮 collector.on("end", async () => { // 消息已被删除的话跳过处理 if (!reply.deletable) return; const disabledRow = new Discord.MessageActionRow().addComponents( row.components.map(btn => btn.setDisabled(true)) ); await reply.edit({ components: [disabledRow] }); }); } if ( msg === "itaru hashida" || msg === "itaru" || msg === "hashida" ) { await cinfo( info.Itaru_Hashida[0], info.Itaru_Hashida[1], info.Itaru_Hashida[2], info.Itaru_Hashida[3], info.Itaru_Hashida[4], info.Itaru_Hashida[5], info.Itaru_Hashida[6], info.Itaru_Hashida[7], info.Itaru_Hashida[8], info.Itaru_Hashida[9], info.Itaru_Hashida[10], info.Itaru_Hashida[11], info.Itaru_Hashida[12] ); } else { // 未匹配到卡牌的提示 await interaction.reply({ content: "未找到对应卡牌信息", ephemeral: true }); } } };
注意事项
- 代码中默认将卡牌名参数改为必填,避免空值导致报错,不需要的话可以改回
setRequired(false)并补充空值处理逻辑 - 分页默认做了循环切换处理,不需要循环的话可自行修改
currentIndex的边界判断逻辑 - 收集器超时时间设为5分钟,可根据需求调整
time参数的数值
内容的提问来源于stack exchange,提问作者lollipop
相关产品推荐
相关产品推荐

