You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Discord.js v14按钮交互失败,mapBanCollector未触发求助

Discord.js v14 地图禁用按钮交互失败问题排查

问题现象

  • 点击地图禁用按钮后,Discord提示「交互失败」
  • 自定义mapBanCollector未触发,console.log('The mapBanCollector is working!')无输出
  • 预期功能:允许1队队长从地图池禁用1张地图,随后在聊天显示被禁用地图

核心问题点

  1. Collector绑定对象错误
    你使用interaction.channel.createMessageComponentCollector监听频道内所有按钮,但按钮实际挂载在编辑后的特定回复消息上。频道级collector无法精准匹配目标按钮,导致触发失败。

  2. 未及时响应交互
    Discord要求所有组件交互必须在3秒内进行ack(如deferUpdate()/update()),若collector未触发,交互会因超时直接提示失败。

  3. 变量作用域错误
    banButton是forEach循环内的局部变量,在collector的collect事件中访问banButton.customId会直接抛出引用错误,阻断逻辑执行。

  4. 组件更新逻辑混乱
    直接修改原有ActionRow和Embed实例后未重新构建完整组件数组,导致Discord无法识别更新内容;且仅传递单个禁用按钮,而非完整的组件结构。

  5. 未定义变量引用
    end事件中直接使用bannedMap变量,但该变量未在事件作用域内定义,会触发报错。

修复后的关键代码

const shuffledQueue = [...queue].sort(() => Math.random() - 0.5);
const captains = [shuffledQueue[0], shuffledQueue[1]];
const team1Captain = captains[0]; 
const mapPool = ['Bind','Haven','Split','Ascent','Icebox','Breeze','Fracture','Pearl','Lotus'];
const MAX_MAPS_TO_BAN = 1; 
let mapBanCount = 0;

const mapBanButtons = [];
mapPool.forEach((map) => {
  const banButton = new ButtonBuilder()
    .setCustomId(`ban_${map}`)
    .setLabel(map)
    .setStyle(ButtonStyle.Danger)
    .setDisabled(false);
  mapBanButtons.push(banButton);
});

const actionRow1 = new ActionRowBuilder().addComponents(mapBanButtons.slice(0, 3));
const actionRow2 = new ActionRowBuilder().addComponents(mapBanButtons.slice(3, 6));
const actionRow3 = new ActionRowBuilder().addComponents(mapBanButtons.slice(6, 9));

const mapBanPhase1Embed = new EmbedBuilder()
  .setTitle('Map Ban Phase')
  .setDescription(`${team1Captain.username}, please ban a map.`)
  .addFields({name: 'Maps', value: mapPool.join('\n')});

// 编辑回复并保存消息实例
const targetMessage = await interaction.editReply({
  embeds: [mapBanPhase1Embed],
  components: [actionRow1, actionRow2, actionRow3],
});

// 绑定collector到目标消息,而非频道
const mapBanCollector = targetMessage.createMessageComponentCollector({
  componentType: ComponentType.Button,
  time: 180000,
  filter: (i) => i.user.id === team1Captain.id,
});

mapBanCollector.on('collect', async (buttonInteraction) => {
  // 立即ack响应,避免交互超时失败
  await buttonInteraction.deferUpdate();

  console.log('The mapBanCollector is working!');

  if (mapBanCount >= MAX_MAPS_TO_BAN) return;

  // 从当前交互按钮获取禁用地图
  const bannedMap = buttonInteraction.customId.split('_')[1];
  console.log(`${team1Captain.username} has banned ${bannedMap}.`);

  // 更新对应按钮为禁用状态
  const btnIndex = mapBanButtons.findIndex(btn => btn.customId === buttonInteraction.customId);
  if (btnIndex !== -1) {
    mapBanButtons[btnIndex].setDisabled(true);
    // 重新构建完整的ActionRow数组
    const updatedRows = [
      new ActionRowBuilder().addComponents(mapBanButtons.slice(0,3)),
      new ActionRowBuilder().addComponents(mapBanButtons.slice(3,6)),
      new ActionRowBuilder().addComponents(mapBanButtons.slice(6,9)),
    ];

    // 更新Embed内容
    const updatedPool = mapPool.filter(map => map !== bannedMap);
    mapBanPhase1Embed.setDescription(`${team1Captain.username} has banned ${bannedMap}.`);
    mapBanPhase1Embed.setFields({name: 'Maps', value: updatedPool.join('\n')});

    mapBanCount++;
    if (mapBanCount >= MAX_MAPS_TO_BAN) {
      // 结束阶段,移除所有组件
      await interaction.editReply({
        embeds: [mapBanPhase1Embed],
        components: [],
      });
      mapBanCollector.stop();
    } else {
      await interaction.editReply({
        embeds: [mapBanPhase1Embed],
        components: updatedRows,
      });
    }
  }
});

mapBanCollector.on('end', async (collected) => {
  // 从收集到的交互中获取禁用地图(若有)
  const bannedMap = collected.first() ? collected.first().customId.split('_')[1] : 'no map';
  console.log(`Captain A has banned ${bannedMap}.`);

  // 后续地图选择逻辑(略)
  // 注意:所有交互更新需确保消息存在,避免报错
});

额外注意事项

  • 需从discord.js导入ComponentType,v14要求明确指定组件类型
  • 所有异步操作必须使用await,避免未处理的Promise导致逻辑异常
  • 测试时可在filter函数中添加日志,确认是否有触发过滤逻辑
  • 避免直接修改原有的Embed/组件实例,必要时创建副本后修改

内容的提问来源于stack exchange,提问作者Shadow

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 15:45:14