首页 > 解决方案 > 如何根据 Discord.js 中的反应编辑消息(创建列表和切换页面)

问题描述

我希望我的 Discord 机器人发送一条消息,然后在人们做出反应时对其进行编辑(例如创建一个列表,然后单击向右或向左箭头将编辑消息并显示列表的下一个/上一个部分)。

示例:
反应前:
在此处输入图像描述

反应后:
在此处输入图像描述

标签: discorddiscord.js

解决方案


如何处理消息反应?

有 3 种方法可以对消息反应做出反应:

  1. 使用函数awaitReactions(基于承诺)
  2. 用一个ReactionCollector
  3. 使用messageReactionAdd事件

区别:

messageReactionAdd是一个链接到的事件Client

每当将反应添加到缓存消息时发出。

while a ReactionCollectorandawaitReactions链接到特定消息,如果将反应添加到另一条消息,则不会执行任何操作。

messageReactionAdd如果将反应添加到缓存消息(旧消息)中,则不会触发。Discord.js 指南中有一个关于收听旧消息的指南,其中给出了此警告

本节介绍如何使用一些未记录的 API 将不支持的功能添加到 discord.js,因此您应该非常小心地遵循此处的任何内容。此处的任何内容都可能随时更改,恕不另行通知,并且可能会破坏您机器人中的其他功能。

awaitReactions是基于 Promise 的,它只会在 Promise 解决时返回所有添加的反应的集合(在添加 X 反应之后,在 Y 秒之后,等等)。没有特定的支持来处理每个添加的反应。您可以将您的函数放在函数中filter以添加每个反应,但这不是有意的小技巧。然而ReactionCollector,有一个collect事件。

那么,我用什么?

您想编辑机器人发送的消息(因为您无法编辑其他用户的消息)。所以ReactionCollectorawaitReactions

如果您想在满足特定条件后编辑消息(X 人已投票,已添加 Y 反应,15 分钟后,...)(例如:投票,您将允许用户在 15 分钟内投票),您可以同时使用awaitReactionsReactionCollector

但是,如果您想根据特定反应编辑消息(如示例中对箭头表情符号做出反应时),则必须使用ReactionCollector.

如果消息没有被缓存,你可以使用messageReactionAdd,但它会更复杂,因为你基本上必须重写一个表情符号收集器,但对于每个表情符号。

注意:如果机器人重新启动, ReactionCollectorandawaitReactions将被删除,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));
}

推荐阅读