Discord.js机器人多Help命令按钮交互异常问题求助
Discord机器人Help命令多实例交互异常问题
问题现象:调用两次及以上Help命令时,仅最后一次调用的命令能正确处理按钮交互,其余命令的交互均出现异常。Help命令通过StringSelectMenu划分多个子菜单,每个子菜单包含同一类命令的若干分页内容。
问题示例
- 两次调用
/help命令后,操作第一个命令的按钮:进入子菜单最后一页时,"Next"和"Last"按钮未按预期禁用;返回第一页时也存在类似异常。但最后一次调用的命令功能完全正常。
问题原因分析
currentPage为静态共享变量,当第二次调用命令时,只有第二个命令实例能更新currentPage的值,所有命令实例共享同一个currentPage,导致之前的命令被迫使用最后一个实例的currentPage值,引发分页索引异常。
预期行为
- 用户选择新子菜单时,自动禁用"First"和"Previous"按钮;若子菜单有多页,则启用"Next"和"Last"按钮,否则禁用所有按钮
- 用户进入子菜单最后一页时,自动禁用"Next"和"Last"按钮
- 用户回到子菜单第一页时,自动禁用"Previous"和"First"按钮
- 用户处于中间页时,所有按钮均启用
已尝试方案
- 基于
interaction.id为每个按钮创建唯一ID - 打印
currentPage值以追踪其变化 - 检查按钮状态更新逻辑
- 查找他人解决方案但无效
- 创建会话为用户分配独立的
currentPage实例 - 使用立即执行函数表达式(IIFE)限制作用域
核心代码片段
以下是按钮交互与分页索引更新的核心代码:
// Handling received interactions from the collector collector.on("collect", async (i) => { if (i.user.id == interaction.user.id) { // If the interaction received is not from the buttons nor from the select menu, do nothing. if (!i.isButton() && !i.isStringSelectMenu()) return; // Defer the reply since the command takes longer time than usual to complete await i.deferUpdate(); // Button handling starts here if (i.isButton()) { // If the user is still on the starting menu, disable all the buttons if (currentCategory == menu.init) { for (const i of buttons) { await i.setDisabled(true); } // User is not on the starting menu } else { // Update the page according to the interaction of the user switch (i.customId) { case "previous": currentPage -= 1; break; case "next": currentPage += 1; break; case "first": currentPage = 0; break; case "last": currentPage = currentCategory.length - 1; break; default: handleError( i, "Unknown button interaction." ); } // Disabled and enable certain buttons to avoid errors // First page if (currentPage == 0) { await previousBtn.setDisabled(true); await firstBtn.setDisabled(true); // Re-enable in case disabled await nextBtn.setDisabled(false); await lastBtn.setDisabled(false); // Last page } else if ( currentPage == currentCategory.length - 1 ) { await nextBtn.setDisabled(true); await lastBtn.setDisabled(true); // Re-enable in case disabled await previousBtn.setDisabled(false); await firstBtn.setDisabled(false); // Middle pages } else { // Reenable all buttons in case disabled for (const button of buttons) { await button.setDisabled(false); } } console.log("BTN:", currentPage); // Update the embed message; await i.editReply({ embeds: [currentCategory[currentPage]], components: [selectMenuRow, buttonsRow], }); } // Select Menu Handling } else if (i.isStringSelectMenu()) { // i.values[0] is the command category that the user had chosen switch (i.values[0]) { case "fun": currentCategory = menu.fun; break; case "utils": currentCategory = menu.utilities; break; case "welcomebye": currentCategory = menu.welcome_goodbye; break; default: currentCategory = menu.init; break; } currentPage = 0; // Reset the page number // Disable the previous and next buttons to avoid unexpected interactions await firstBtn.setDisabled(true); await previousBtn.setDisabled(true); // If there are more than one page of help in that category, allow the user to move on the next pages if (currentCategory.length > 1) { await nextBtn.setDisabled(false); await lastBtn.setDisabled(false); // If there is only one page of help, disable all the buttons to prevent causing errors } else { await nextBtn.setDisabled(true); await lastBtn.setDisabled(true); } await interaction.editReply({ embeds: [currentCategory[currentPage]], components: [selectMenuRow, buttonsRow], }); } // A non-command-caller user tries to interact with the command } else { await i.deferUpdate(); await i.followUp({ content: `This is not for you.`, ephemeral: true, }); } });
内容的提问来源于stack exchange,提问作者TommyYOyoyo
相关产品推荐
相关产品推荐

