Discord Bot嵌入消息返回undefined问题求助
我刚仔细看了你的代码和问题截图,发现两个核心问题导致变量显示undefined,咱们一步步来解决:
问题根源
1. 变量作用域不匹配
你在模态框提交的回调里定义了ginputdata和sinputdata,但这两个变量是该回调函数的局部变量。当用户后续选择下拉菜单时,触发的是另一个独立的回调函数,根本访问不到之前定义的这两个变量,自然就显示undefined了。
2. 重复绑定全局监听器
每次运行sendspielersuche命令,你的代码都会给client添加新的interactionCreate监听器。这会导致后续的交互被多次处理,不仅逻辑混乱,还会浪费资源。
解决方案:用临时存储+独立交互收集器
推荐用Map来存储用户的临时输入(避免全局变量被多用户操作覆盖),同时改用MessageComponentCollector替代全局监听器,每个交互链都是独立的一次性监听。
修改后的完整代码如下:
const Discord = require('discord.js') const Command = require('../../structures/CommandClass'); const { stripIndents } = require('common-tags'); const { SlashCommandBuilder, PermissionFlagsBits, EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle, TextInputStyle, StringSelectMenuBuilder, Events, ModalBuilder, TextInputBuilder } = require('discord.js'); module.exports = class spielersuche extends Command { constructor(client) { super(client, { data: new SlashCommandBuilder() .setName('sendspielersuche') .setDescription('Sende das Spielersuche Embed') .setDefaultMemberPermissions(PermissionFlagsBits.BanMembers) .setDMPermission(false), }); } async run(client, interaction) { const member = await interaction.member.fetch(); const anfragechannelID = '889302458906591344'; const anfragechannel = member.guild.channels.cache.get(anfragechannelID); const createanfragechannelID = '1061113274130772058'; const createanfragechannel = member.guild.channels.cache.get(createanfragechannelID); // 用来临时存储用户输入的Map,键是用户ID,值是输入的理由和游戏 const userTempData = new Map(); // 平台选择下拉菜单 const platformMenu = new ActionRowBuilder() .addComponents( new StringSelectMenuBuilder() .setCustomId('pfmenü') .setPlaceholder('Plattform auswählen') .addOptions( { label: 'PS4', value: 'ps4' }, { label: 'PS5', value: 'ps5' }, { label: 'PS4/PS5', value: 'ps4ps5' }, { label: 'PC', value: 'pc' }, { label: 'Switch', value: 'switch' }, { label: 'Alle', value: 'alle' }, ), ); // 游戏和理由输入模态框 const requestModal = new ModalBuilder() .setCustomId('minput') .setTitle('Spielersuche 🔎'); const gameInput = new TextInputBuilder() .setCustomId('spielinput') .setLabel("Für welches Spiel?") .setPlaceholder('GTA5, Fortnite, Call of Duty, Minecraft ...') .setStyle(TextInputStyle.Short) .setMinLength(2) .setMaxLength(20) .setRequired(true); const reasonInput = new TextInputBuilder() .setCustomId('grundinput') .setLabel("Der Grund der Anfrage?") .setPlaceholder('Beispiel: Suche Spieler für Cayo Perico Heist.') .setStyle(TextInputStyle.Short) .setMinLength(10) .setMaxLength(60) .setRequired(true); const gameRow = new ActionRowBuilder().addComponents(gameInput); const reasonRow = new ActionRowBuilder().addComponents(reasonInput); requestModal.addComponents(gameRow, reasonRow); // 主Embed和触发按钮 const mainEmbed = new EmbedBuilder() .setTitle(`Spieler suchen Spieler 🔎`) .setColor('#00ff0c') .setDescription(stripIndents`Drücke auf denn Button um eine Spielersuche Anzufragen!`) .setFooter({ text: 'YANKEEUNIT91 COMMUNITY'}) .setTimestamp(); const requestButton = new ActionRowBuilder() .addComponents( new ButtonBuilder() .setCustomId('buttonanfrage') .setEmoji('🔎') .setLabel('Spielersuche Anfragen') .setStyle(ButtonStyle.Success), ); // 发送主Embed到指定频道 const sentMainMsg = await createanfragechannel.send({ embeds: [mainEmbed], components: [requestButton] }); await interaction.reply({ content: 'Spielersuche Embed wurde versendet!', ephemeral: true }); // 监听按钮点击(一次性收集器,避免全局监听器重复绑定) const buttonCollector = sentMainMsg.createMessageComponentCollector({ filter: i => i.customId === 'buttonanfrage' && i.user.id !== client.user.id, time: 86400000 // 24小时后自动过期 }); buttonCollector.on('collect', async buttonInt => { // 打开模态框 await buttonInt.showModal(requestModal); // 监听模态框提交 const modalCollector = buttonInt.channel.createModalSubmitCollector({ filter: modalInt => modalInt.customId === 'minput' && modalInt.user.id === buttonInt.user.id, time: 300000 // 5分钟未提交则过期 }); modalCollector.on('collect', async modalInt => { // 获取用户输入的理由和游戏 const userReason = modalInt.fields.getTextInputValue('grundinput'); const userGame = modalInt.fields.getTextInputValue('spielinput'); // 把数据存到Map里,用用户ID做键 userTempData.set(modalInt.user.id, { reason: userReason, game: userGame }); // 回复用户让其选择平台 await modalInt.reply({ content:'**Wähle deine Plattform!**', components: [platformMenu], ephemeral: true }); // 监听平台下拉菜单选择 const selectCollector = modalInt.channel.createMessageComponentCollector({ filter: selectInt => selectInt.customId === 'pfmenü' && selectInt.user.id === modalInt.user.id, time: 300000 // 5分钟未选择则过期 }); selectCollector.on('collect', async selectInt => { const selectedPlatform = selectInt.values.join(', '); // 从Map里取出当前用户的输入数据 const userData = userTempData.get(selectInt.user.id); // 容错处理:如果没找到数据就提示错误 if (!userData) { return await selectInt.reply({ content: 'Fehler: Keine Eingabedaten gefunden! Bitte starte die Anfrage neu.', ephemeral: true }); } // 构建最终的Embed const finalEmbed = new EmbedBuilder() .setTitle(`${userData.reason}`) .setColor('#00ff0c') .setFooter({ text: 'YANKEEUNIT91 COMMUNITY'}) .setTimestamp() .addFields( { name: '**Spiel:**', value: `${userData.game}`, inline: true, }, { name: `**Plattform:**`, value: `${selectedPlatform}`, inline: false, }, ); // 更新用户的回复,发送最终Embed到指定频道 await selectInt.update({ content:'**Spielersuche erfolgreich Angefragt!**', components: [], ephemeral: true }); await anfragechannel.send({ content: `**Anfrage von:** <@${selectInt.user.id}>`, embeds: [finalEmbed] }); // 从Map里删除已处理的数据,释放内存 userTempData.delete(selectInt.user.id); }); }); }); } };
核心改进说明
- 解决作用域问题:用
Map存储每个用户的输入数据,确保下拉菜单回调能精准获取到当前用户的理由和游戏信息,不会出现undefined。 - 避免重复监听器:改用
MessageComponentCollector和ModalSubmitCollector,每个交互链都是独立的一次性监听,不会因为多次运行命令而堆积监听器。 - 并发安全:每个用户的数据单独存储,多个用户同时操作时不会互相覆盖数据。
- 容错处理:增加了数据不存在时的错误提示,提升用户体验。
- 内存优化:用户完成操作后自动删除临时数据,避免内存浪费。
直接替换你原代码中的run函数部分,测试后应该就能解决变量显示undefined的问题了。
内容的提问来源于stack exchange,提问作者Marc-Anthony
相关产品推荐
相关产品推荐

