如何检查用户是否正在与选择菜单交互并在 Discord.js v13 中禁用它
我希望当用户与选择菜单交互时它应该工作,然后当用户停止与其交互时几秒钟后它应该禁用它。
这就是 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("
I want that when the user is interacting with the select menu it should work and then it should disable it after a few seconds when the user stops interacting with it.
This is just the idea how the Dank Memer bot Help command work.
What my command is doing:
The command works as a help command that is getting all the files in the sub-folder of the command folder and giving the usage, name and description of the command. It edits the embed when the user selects an option in select menu and the option are the sub-folders of the command folder.
So I have done this till now:
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);
}
}
}
}
});
});
}
}
There are no errors till now.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
正如我在评论中提到的,看起来您想要做的就是在收集器之前声明一个空变量(例如,名为
timeout
),并且每次收集器收集您所做的事情时如果定义了
,然后将timeout
,则clearTimeout(timeout)timeout
设置为等于当前的setTimeout()
语句。也就是说,如果我正确理解你的问题。忽略我关于将超时完全移到收集器之外的最初评论,因为这可能不是您在问题中寻找的内容(我相信我最初误解了您的问题 - 但是,如果这个答案仍然不是您想要的,我最初的评论可能正是您正在寻找的)。现在回答你的问题。这是我在上面和评论中描述的过程的一个例子。我只是要显示代码的相关部分,以便您知道所有事情都发生在哪里,而不必筛选数十行来查找我的更改(并在将来注意,请仅包含代码中发生的部分)与您的问题相关——即在本例中只是您的收集器和
collector.on("collect")
处理程序)。以下是这段代码的作用,一步一步。每次用户与选择菜单交互时:
超时
是否已启动。如果是这样,请将其清除。 (如果尚未创建超时,则无需清除超时)。setTimeout()
创建新的超时
。新的超时将在 6 秒后禁用选择菜单。为了回应您对我在评论中试图告诉您的内容感到困惑的评论,我希望这个逐步的解释能够澄清我的意思。
编辑
删除了检查大小写
!i.message.member.id === i.isSelectMenu()
的if
语句。正如我在评论中所解释的,这里!i.message.member.id
始终为false
,而i.isSelectMenu()
始终为 < code>true 在这里,因此删除的if
语句正在检查 iffalse === true
(这显然是一个始终为 false 的语句)。编辑2
正如我在关于这个问题的第一个评论中提到的,即OP感到困惑的最初评论,原始的超时功能位于收集器内部。这意味着禁用选择菜单和按钮的所有代码仅在最初选择菜单中的值后才会执行。换句话说,6秒无交互后菜单不会自行禁用;它只会在最后一次交互后 6 秒自行禁用。如果用户根本没有使用选择菜单,则 6 秒后不会发生禁用。这就是我原来的评论的意思。我修改了答案,将初始超时移到收集器之外。现在,如果用户出现以下情况,它将在 6 秒后禁用: a) 根本没有进行交互;或 b) 最后一次互动是在 6 秒前。
As I mentioned in my comment, it looks like all you want to do is declare an empty variable (for example, named
timeout
) before your collector, and each time the collector collects something you doclearTimeout(timeout)
iftimeout
is defined, and then afterwards you settimeout
equal to your currentsetTimeout()
statement. That is, if I'm understanding your question correctly. Ignore my initial comment about moving the timeout entirely outside the collector, as that was probably not what you were looking for with your question (I believe I initially misunderstood your question -- however, if this answer is still not what you are looking for, my initial comment may instead be exactly what you are looking for).Now for the answer to your question. Here is an example of what I am talking about with the process I described above and in the comments. I'm just going to show the relevant parts of the code so that you know where everything is happening, without having to sift through dozens of lines to find my changes (and note in the future, please only include the parts of your code that are relevant to your question -- i.e. just your collector and the
collector.on("collect")
handler in this case).Here is what this code does, step by step. Every time a user interacts with the select menu:
timeout
has already been started. If so, clear it. (If no timeout has been created yet, no clearing of timeouts needs to occur).timeout
usingsetTimeout()
. The new timeout will disable the select menu after 6 seconds.In response to your comment expressing confusion over what I was trying to tell you in the comments, I hope this step-by-step explanation clears up what I meant.
Edit
Removed the
if
statement that checks the case!i.message.member.id === i.isSelectMenu()
. As I explained in the comments,!i.message.member.id
is alwaysfalse
here, andi.isSelectMenu()
is alwaystrue
here, so the removedif
statement was checking iffalse === true
(which is obviously a statement that is always false).Edit 2
As I mentioned in my very first comment on this question, i.e. the initial comment that the OP was confused about, the original timeout functionality was inside the collector. This meant that all of the code to disable the select menu and button would only execute after a value in the menu was initially selected. In other words, the menu would not disable itself after 6 seconds of no interaction; it would only disable itself 6 seconds after the last interaction. If the user did not use the select menu at all, no disabling would occur after 6 seconds. This is what I meant with my original comment. I have modified the answer to move the initial timeout outside the collector. Now, it will disable after 6 seconds if the user either: a) has not interacted at all; or b) last interacted over 6 seconds ago.
为此,您需要在收集器中添加
idle: amount
,其中 amount 是您的时间(以毫秒为单位)。这将在上次交互后 6 秒后或启动命令后 6 秒后停止收集器。
您还可以使用
time: amount
在经过特定时间后停止收集器。To achieve that you need to add
idle: amount
, where amount is your time in milliseconds, in your collector.This will stop the collector after 6 seconds from the last interaction, or 6 seconds after the command being launched.
You can also use
time: amount
to stop the collector after a specific amount of time passes.