如何检查用户是否正在与 select 菜单交互并在 discord.js v13 中禁用它

How do I check if the user is interacting with select menu and disable it in discord.js v13

我希望当用户与 select 菜单交互时,它应该可以工作,然后在用户停止与之交互几秒钟后将其禁用。

这就是 Dank Memer bot Help 命令的工作原理。

我的命令在做什么: 该命令用作帮助命令,获取命令文件夹子文件夹中的所有文件,并给出命令的用法、名称和描述。当用户 select 在 select 菜单中有一个选项并且该选项是命令文件夹的子文件夹时,它会编辑嵌入。

到目前为止,我一直这样做:

const { MessageEmbed, Message, MessageActionRow, MessageSelectMenu, MessageButton } = require("discord.js");
const fs = require("fs");
const prefix = require("../../config.json").PREFIX;

module.exports = {
  name: "help",
  description: "Get All The Commands!",
  usage: "help",
  cooldown: 1000 * 5,
  category: "Help Commands!",
  /**
   * @param {Message} message
   * 
   */
  run: async (client, message, args) => {
    const sizeOfCat = fs.readdirSync("./Commands - Staff/");

    const OldEmbed = new MessageEmbed()
      .setAuthor({
        name: "Commands! =>",
        iconURL: `${message.guild.iconURL({ dynamic: true })}`
      })
      .setThumbnail(`${message.guild.iconURL({ dynamic: true })}`)
      .setTitle(" Need help? Select The Category You Want To =>")
      .setDescription(
        `
        **\`Hello Dear ${message.member.user.username}, Please Select Your Category According To Your Choice!\`**

        **How To Use =>**
        \`1) Click The Select Menu Down Below.\`
        \`2) You Will See Many Categories, Click Your Category You Want To View.\`
        \`3) The Embed Will Be Edited And You Can See Your Commands According To Category.\`

        *Note => The Select Menu And The Button Will Be Disabled Automatically After 6 Seconds!*

        **Total Categories Are: ${sizeOfCat.length}**
        `
      )
      .setColor("BLURPLE")
      .setTimestamp()
      .setFooter({
        text: `Requested by ${message.author.tag}`, 
        iconURL: message.author.displayAvatarURL({ dynamic: true })
      })

      const homeButton = new MessageActionRow()
      .addComponents(
        new MessageButton()
        .setCustomId("Home")
        .setLabel("Back To Home!")
        .setStyle("PRIMARY")
        .setEmoji("️")
      )

      const EmojisCat = {
        "Other Commands!": "",
        "Help Commands!": "",
        "Moderation Commands!": "⚒️",
        "Owner Commands!": ""
      };

      const selectMenu = new MessageActionRow()
      .addComponents(
        new MessageSelectMenu()
        .setCustomId("Help-Menu")
        .setPlaceholder(`Click To View The Categories Of The Commands!`)
        .addOptions([
          client.categoriesCommands.map((cat) => {
            return {
              label: `${cat[0].toUpperCase() + cat.slice(1)}`,
              value: cat,
              emoji: EmojisCat[cat],
              description: `Click To View The Commands Of This Categories!`,
            }
          })
        ])
      );

    await message.reply({
      content: "**There You Go, Check The List Of Categories!**",
      embeds: [OldEmbed],
      components: [selectMenu, homeButton]
    })
    .then(async (msg) => {

      let filter = i => i.member.id === message.member.id;
      let colletor = msg.createMessageComponentCollector({ filter: filter });

      let timeout = null;
      colletor.on("collect", async (i) => {
        if (!i.member.id === message.member.id) {
          await msg.reply({
            content: `**Its Not Your Turn Of Using The Command Menu Or The Command (\`${prefix}help\`) Is Not Runned By You! Dum Dum.**`,
            ephemeral: true,
          });
        } else {

          if (i.isButton()) {
            await i.deferUpdate();
            if (i.customId === "Home") {
              msg.edit({ embeds: [OldEmbed] })
            }
          }

          if (i.isSelectMenu()) {
            if (i.customId === "Help-Menu") {
              await i.deferUpdate();
              let [ directory ] = i.values;
              let totalCdms = client.categoriesCommands.filter(cmd => cmd.category === directory).map(cmd => cmd.size);
              let command = client.categoriesCommands.filter(cmd => cmd.category === directory).map(cmd => cmd.length) + 1;

              const embed = new MessageEmbed()
                .setAuthor({
                  name: "AwesomeSMP Commands! =>",
                  iconURL: `${message.guild.iconURL({ dynamic: true })}`
                })
                .setThumbnail(`${message.guild.iconURL({ dynamic: true })}`)
                .setTitle(` Need help? Here Are All Of My ${directory} Commands:`)
                .setDescription(
                  `
                  **\`Here Are One Of My [${directory} Category] Commands =>\`**

                  **Total Commands In ${directory} Are: ${totalCdms}**
                  `
                )
                .setColor("BLURPLE")
                .setTimestamp()
                .setFooter({
                  text: `Requested by ${message.author.tag}`, 
                  iconURL: message.author.displayAvatarURL({ dynamic: true })
                })
                
              client.commands.filter((cmd) => cmd.category === directory)
              .map((cmd) => {
                embed.addField(
                  `\n**\nCommmand-${command++}** =>\n\`${prefix}${cmd.name}\``,
                  `   **Description:** *${cmd.description.toUpperCase() || "*None*"}*\n   **Usage:** *${prefix} ${cmd.usage || "None"}*\n`
                  ,true
                );
              })

              await msg.edit({
                embeds: [embed]
              });
              
              if (!i.message.member.id === i.isSelectMenu()) {
                if (timeout) clearTimeout(timeout);
                timeout = setTimeout(async () => {
                  selectMenu.components[0].setDisabled(true);
                  homeButton.components[0].setDisabled(true);
          
                  await msg.edit({
                    embeds: [OldEmbed],
                    components: [selectMenu, homeButton]
                  });
                }, 6000);
              }

            }
          }
        }
      });
    });
  }
}

到目前为止没有错误。

正如我在评论中提到的,看起来你想要做的就是在你的收集器之前声明一个空变量(例如,命名为 timeout),每次收集器收集你做的事情clearTimeout(timeout) 如果定义了 timeout,然后你设置 timeout 等于你当前的 setTimeout() 语句。也就是说,如果我正确理解你的问题。忽略我最初关于将超时完全移到收集器之外的评论,因为这可能不是您要寻找的问题(我相信我最初误解了您的问题——但是,如果这个答案仍然不是您要找的,我最初的评论可能正是您要找的)。

现在回答你的问题。这是我在上面和评论中描述的过程中谈论的示例。我将只展示代码的相关部分,以便您了解一切发生的位置,而不必筛选几十行代码来查找我的更改(并且请注意,以后请只包含您的代码部分与您的问题相关 - 即在这种情况下只是您的收集器和 collector.on("collect") 处理程序)。

async function disableAll() {
    selectMenu.components[0].setDisabled(true);
    homeButton.components[0].setDisabled(true);
  
    await msg.edit({
        embeds: [OldEmbed],
        components: [selectMenu, homeButton]
    });
}

let timeout = setTimeout(disableAll, 6000);
colletor.on("collect", async (i) => {
               
    if (timeout) clearTimeout(timeout);
    timeout = setTimeout(disableAll, 6000);

});

这是这段代码的作用,一步一步。每次用户与 select 菜单交互时:

  1. 检查 timeout 是否已经启动。如果是这样,请清除它。 (如果尚未创建超时,则不需要清除超时)。
  2. 使用 setTimeout() 创建一个新的 timeout。新超时将在 6 秒后禁用 select 菜单。
  3. 如果用户在 6 秒结束之前再次与 select 菜单交互,则该过程从步骤 1 重新开始。上一步中创建的超时将被清除,另一个将在它的位置,时间重置为 6 秒。
  4. 如果在 6 秒结束之前没有用户再次与 select 菜单交互,则一旦时间用完,select 菜单就会被禁用。这意味着菜单只会在用户最后一次与菜单交互后 6 秒禁用。

为了回应你对我在评论中试图告诉你的内容表示困惑的评论,我希望这个 step-by-step 解释能澄清我的意思。

编辑

删除了检查大小写 !i.message.member.id === i.isSelectMenu()if 语句。正如我在评论中解释的那样,!i.message.member.id 在这里总是 false,而 i.isSelectMenu() 在这里总是 true,所以删除的 if 语句正在检查是否 false === true(这显然是一个总是错误的陈述)。

编辑 2

正如我在对这个问题的第一条评论中提到的,即 OP 感到困惑的最初评论,最初的超时功能在收集器内部。这意味着所有禁用 select 菜单和按钮的代码只会在菜单中的值最初被 selected 后执行。换句话说,菜单不会在 6 秒无交互后自行禁用;它只会在最后一次交互后 6 秒后自行禁用。如果用户根本没有使用 select 菜单,则 6 秒后不会发生禁用。这就是我最初评论的意思。我修改了答案以将初始超时移到收集器之外。现在,如果用户出现以下情况,它将在 6 秒后禁用:a) 根本没有交互;或 b) 最后一次互动是在 6 秒前。