【问题标题】:How do I check if the user is interacting with select menu and disable it in discord.js v13如何检查用户是否正在与选择菜单交互并在 discord.js v13 中禁用它
【发布时间】:2022-07-17 01:34:33
【问题描述】:

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

这只是 Dank Memer 机器人帮助命令的工作原理。

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

所以我一直这样做到现在:

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);
              }

            }
          }
        }
      });
    });
  }
}

到目前为止没有错误。

【问题讨论】:

  • 在不活动后禁用组件的超时在收集器的collect 处理程序中,这意味着不活动超时只会在收集任何输入之后开始。我假设您希望此超时在收集器之外,因此即使没有收集到输入,它也会在超时后自行禁用。
  • 我不明白@Cannicide 想说什么。他是否告诉我将我的超时移到收集器之外,我还写过我希望我的帮助命令作为 Dank Memer 帮助命令工作。因此,如果他们不知道 Dan​​k Memer 是什么,我建议他们使用那里的帮助命令并检查当用户停止与下拉菜单交互时,几秒钟后下拉菜单会自行禁用。
  • “互动”到底是什么意思?你的意思是“用户最后选择一个值后x秒,禁用菜单”的意思吗?您说,“如果他们不知道 Dan​​k Memer 是什么,我会建议他们使用那里的帮助命令并检查”,但是如果您只是在问题本身中包含高度相关的信息而不是要求回答者,那么回答者会容易得多我们让 Dank Memer 自己尝试这个命令。我同意@halfer 的观点,大多数读者可能不明白你想做什么。
  • 根据您所说的,我认为您正在寻找的只是在您的收集器之前声明一个空变量(例如,名为timeout),并且每次收集器收集您所做的事情clearTimeout(timeout) 如果定义了timeout,然后你将timeout 设置为等于你当前的setTimeout() 语句。每次选择菜单值时,这基本上都会重置超时计时器。
  • @Cannicide 我还是不明白._.,你能给我一个例子,这样我就能明白你在说什么?我只是知道你告诉我将我的timeout 移出收集器,如果人们不明白我在说什么,至少你明白了,然后 halfer 可以编辑我的消息并解释更多

标签: node.js drop-down-menu discord.js


【解决方案1】:

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

现在回答您的问题。这是我在上面描述的过程和在 cmets 中谈论的内容的示例。我只是要展示代码的相关部分,以便您知道发生了什么事,而不必筛选数十行来找到我的更改(并且请注意,将来请仅包含您的代码部分与您的问题相关 - 即在这种情况下,只是您的收集器和 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);

});

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

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

为了回应您对我在 cmets 中试图告诉您的内容感到困惑的评论,我希望这个分步说明能够澄清我的意思。

编辑

删除了检查大小写 !i.message.member.id === i.isSelectMenu()if 语句。正如我在 cmets 中解释的那样,!i.message.member.id 在这里始终是 falsei.isSelectMenu() 在此处始终是 true,因此删除的 if 语句正在检查 false === true 是否是假)。

编辑 2

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

【讨论】:

  • 谢谢,我现在明白了,我也会测试一下
  • 嘿,我用了你的方法,但它不起作用你能看到我编辑的代码并告诉我做错了什么,因为它在 6 秒后没有禁用它。
  • 我不确定。您将需要进行一些调试。我相信此答案中使用的逻辑可以正常工作,因此问题很可能是您的代码中实际上从未达到此超时代码。尝试将console.log 放在let timeout = null 行之前,看看它是否记录了任何内容。如果不是,则代码的逻辑有问题,阻止了此代码的执行。问题可能类似于声明 !i.message.member.id === i.isSelectMenu() 没有返回您期望的值(这也可能是一件好事)。
  • 好的,我按照你告诉我的做了,这是timeout 的结果,它说“null”,!i.message.member.id === i.isSelectMenu() 说“false”。
  • 正如我所怀疑的那样。看看你做!i.message.member.id === i.isSelectMenu() 的逻辑。不太确定那条线的意义是什么。 !i.message.member.id 将永远是 false (因为使用选择菜单的成员的 ID 将始终被定义),所以目前超时代码只会在 i.isSelectMenu()false 时执行(但这个语句在一个if (i.isSelectMenu()),所以i.isSelectMenu() 总是true)。所以基本上你在这里有一个if (false === true)。您可能应该删除/编辑该行。试试看,我也会从这个答案中编辑出来。
【解决方案2】:

要实现这一点,您需要在您的收集器中添加“idle:amount”,其中amount 是您的时间(以毫秒为单位)。

let collector = msg.createMessageComponentCollector({ filter: filter, idle: 6000 });

这将在最后一次交互 6 秒后或命令启动后 6 秒后停止收集器。

您还可以使用“时间:数量”在经过特定时间后停止收集器。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-10-28
    • 2022-01-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-16
    • 2022-01-05
    相关资源
    最近更新 更多