discord - 如何根据 Discord.js 中的反应编辑消息(创建列表和切换页面)
问题描述
我希望我的 Discord 机器人发送一条消息,然后在人们做出反应时对其进行编辑(例如创建一个列表,然后单击向右或向左箭头将编辑消息并显示列表的下一个/上一个部分)。
解决方案
如何处理消息反应?
有 3 种方法可以对消息反应做出反应:
- 使用函数
awaitReactions
(基于承诺) - 用一个
ReactionCollector
- 使用
messageReactionAdd
事件
区别:
messageReactionAdd
是一个链接到的事件Client
:
每当将反应添加到缓存消息时发出。
while a ReactionCollector
andawaitReactions
链接到特定消息,如果将反应添加到另一条消息,则不会执行任何操作。
messageReactionAdd
如果将反应添加到缓存消息(旧消息)中,则不会触发。Discord.js 指南中有一个关于收听旧消息的指南,其中给出了此警告
本节介绍如何使用一些未记录的 API 将不支持的功能添加到 discord.js,因此您应该非常小心地遵循此处的任何内容。此处的任何内容都可能随时更改,恕不另行通知,并且可能会破坏您机器人中的其他功能。
awaitReactions
是基于 Promise 的,它只会在 Promise 解决时返回所有添加的反应的集合(在添加 X 反应之后,在 Y 秒之后,等等)。没有特定的支持来处理每个添加的反应。您可以将您的函数放在函数中filter
以添加每个反应,但这不是有意的小技巧。然而ReactionCollector
,有一个collect
事件。
那么,我用什么?
您想编辑机器人发送的消息(因为您无法编辑其他用户的消息)。所以ReactionCollector
或awaitReactions
。
如果您想在满足特定条件后编辑消息(X 人已投票,已添加 Y 反应,15 分钟后,...)(例如:投票,您将允许用户在 15 分钟内投票),您可以同时使用awaitReactions
和ReactionCollector
。
但是,如果您想根据特定反应编辑消息(如示例中对箭头表情符号做出反应时),则必须使用ReactionCollector
.
如果消息没有被缓存,你可以使用messageReactionAdd
,但它会更复杂,因为你基本上必须重写一个表情符号收集器,但对于每个表情符号。
注意:如果机器人重新启动, ReactionCollector
andawaitReactions
将被删除,whilemessageReactionAdd
将照常工作(但您将丢失已声明的变量,因此如果您存储了要收听的消息,它们也会消失)。
该怎么办?
你需要不同的东西:
- 将触发功能的表情符号列表(您可以选择对每个表情符号做出反应)
- 停止收听消息反应的条件(如果您想收听每条消息,则不适用
messageReactionAdd
- 接收消息并对其进行编辑的功能
- 一个将返回布尔值的过滤器函数:
true
我想对这个表情符号做出反应,false
我不想做出反应。此功能将基于表情符号列表,但也可以过滤用户反应或您需要的任何其他条件 - 编辑消息的逻辑。eg:对于一个列表,它将基于结果的数量、当前索引和添加的反应
示例:用户列表
表情符号列表:
const emojiNext = '➡'; // unicode emoji are identified by the emoji itself
const emojiPrevious = '⬅';
const reactionArrow = [emojiPrevious, emojiNext];
停止条件
const time = 60000; // time limit: 1 min
编辑功能
这里的功能非常简单,消息是预先生成的(时间戳和页脚除外)。
const first = () => new Discord.MessageEmbed()
.setAuthor('TOTO', "https://i.imgur.com/ezC66kZ.png")
.setColor('#AAA')
.setTitle('First')
.setDescription('First');
const second = () => new Discord.MessageEmbed()
.setAuthor('TOTO', "https://i.imgur.com/ezC66kZ.png")
.setColor('#548')
.setTitle('Second')
.setDescription('Second');
const third = () => new Discord.MessageEmbed()
.setAuthor('TOTO', "https://i.imgur.com/ezC66kZ.png")
.setColor('#35D')
.setTitle('Third')
.setDescription('Third');
const list = [first, second, third];
function getList(i) {
return list[i]().setTimestamp().setFooter(`Page ${i+1}`); // i+1 because we start at 0
}
过滤功能
function filter(reaction, user){
return (!user.bot) && (reactionArrow.includes(reaction.emoji.name)); // check if the emoji is inside the list of emojis, and if the user is not a bot
}
逻辑
请注意,我在这里使用 list.length 以避免进入 list[list.length] 及其他范围。如果您没有硬编码列表,您应该在参数中传递一个限制。
如果索引无效,您还可以使 getList 返回 undefined,而不是将索引用于布尔条件,而是将返回的值与 undefined 进行比较。
function onCollect(emoji, message, i, getList) {
if ((emoji.name === emojiPrevious) && (i > 0)) {
message.edit(getList(--i));
} else if ((emoji.name === emojiNext) && (i < list.length-1)) {
message.edit(getList(++i));
}
return i;
}
这是另一个 getList 函数的另一个逻辑,例如它只返回 list[i],而不是像上面那样设置时间戳,因为尝试.setTimestamp
在 undefined 上执行会引发错误。
if (emoji.name === emojiPrevious) {
const embed = getList(i-1);
if (embed !== undefined) {
message.edit(embed);
i--;
}
} else if (emoji.name === emojiNext) {
const embed = getList(i+1);
if (embed !== undefined) {
message.edit(embed);
i++;
}
}
return i;
构建构造函数
示例与问题中的相同,使用箭头功能编辑消息。
我们将使用收集器:
function createCollectorMessage(message, getList) {
let i = 0;
const collector = message.createReactionCollector(filter, { time });
collector.on('collect', r => {
i = onCollect(r.emoji, message, i, getList);
});
collector.on('end', collected => message.clearReactions());
}
它需要我们想听的信息。您还可以给它一个内容列表 // 消息 // 一个数据库 // 任何必要的东西。
发送消息并添加收集器
function sendList(channel, getList){
channel.send(getList(0))
.then(msg => msg.react(emojiPrevious))
.then(msgReaction => msgReaction.message.react(emojiNext))
.then(msgReaction => createCollectorMessage(msgReaction.message, getList));
}
推荐阅读
- angular - @angular/router 的 loadChildren 中的 gen 路径名
- java - 根据条件将常数值分配给不同变量中的一个
- angular-material - 为什么我的不行
加载时是否选择了指定值? - java - htm2pdf itextpdf外部css不生效
- c# - 如何删除列表的元素
与另一个列表相关 ? - c++ - C++中使用向量初始化链表
- sql - 撤销用户对 DROP 表的权限
- php - 订单总额的变量名称是什么(Back-office prestashop 1.7.5)?
- spring-boot-admin - Spring Boot Admin:过滤通知的示例
- python - 在单词级别测量分类器的准确性