Discord开发:如何用Modal响应选择菜单命令及解决交互报错
解决方案:Discord斜杠命令中选择菜单触发Modal的实现
方案一:修复组件交互触发Modal的逻辑
你的核心问题是误用了已完成响应的原始斜杠命令交互来调用showModal。正确的做法是使用选择菜单自身的交互对象(代码中的cld)触发Modal——每个组件交互都是独立的,不受原始斜杠交互的响应限制。
修改后的关键代码片段:
collector.on('collect', async (cld) => { // 先处理组件交互的响应,避免Discord超时警告 await cld.deferUpdate(); if(cld.values[0] === '63960e06ee2ff68635eff3bb'){ // 改用组件交互对象调用showModal await cld.showModal(modal); } })
完整修改后的execute函数:
async execute(interaction, client) { const userRoles = interaction.member.roles.cache.map((role) => role.id) let allMatches = await matches.find() let userMatches = [] allMatches.forEach(element => { userRoles.forEach(role => { if (element._team1 === role || element._team2 === role) { userMatches.push(element) } }) }) const embed = new EmbedBuilder() .setTitle('Select a match') .setColor(0x18e1ee) const componentsMenu = new ActionRowBuilder().addComponents( new StringSelectMenuBuilder() .setCustomId('select') .setPlaceholder('Nothing selected') ) userMatches.forEach(element => { componentsMenu.components[0].addOptions( { label: interaction.guild.roles.cache.get(element._team1).name + ' VS ' + interaction.guild.roles.cache.get(element._team2).name, value: element.id, } ) }) const modal = new ModalBuilder() .setCustomId('test') .setTitle('test2') const textInput = new TextInputBuilder() .setCustomId('test3') .setLabel('test4') .setRequired(true) .setStyle(TextInputStyle.Short) modal.addComponents(new ActionRowBuilder().addComponents(textInput)) const message = await interaction.reply({embeds: [embed], components: [componentsMenu], fetchReply: true}) const collector = message.createMessageComponentCollector({ filter: (u) => u.user.id === interaction.user.id, time: 60000 // 可选:添加超时时间,避免collector长期存在 }) collector.on('collect', async (cld) => { await cld.deferUpdate(); if(cld.values[0] === '63960e06ee2ff68635eff3bb'){ await cld.showModal(modal); } }) collector.on('end', () => { // 可选:超时后禁用选择菜单,提示用户重新发起命令 componentsMenu.components[0].setDisabled(true); interaction.editReply({components: [componentsMenu]}); }) }
方案二:发送普通消息并消除命令错误提示
如果坚持要将选择菜单作为普通消息发送到频道,只需先对斜杠命令做一个私有临时回复(仅用户可见),就能避免Discord弹出未响应命令的错误提示。
修改后的关键代码:
// 先回复斜杠命令,用ephemeral: true让只有用户自己能看到 await interaction.reply({content: '正在生成匹配选择菜单...', ephemeral: true}); // 再发送普通消息到频道 const message = await interaction.channel.send({embeds: [embed], components: [componentsMenu]});
后续的collector逻辑与方案一一致,使用cld.showModal即可。
关键说明
- Discord的每个交互(斜杠命令、组件点击等)仅能被响应一次,原始斜杠交互用
interaction.reply后,不能再用它调用showModal,必须使用组件自身的交互对象。 - 组件交互必须在3秒内完成响应(
deferUpdate、deferReply或直接回复),否则会触发Discord的超时警告,所以一定要添加await cld.deferUpdate()。
内容的提问来源于stack exchange,提问作者Pixyde
相关产品推荐
相关产品推荐

