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

Jac*_*Red 4 discord discord.js

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

例子:
反应前:
在此处输入图片说明

反应后:
在此处输入图片说明

Jac*_*Red 8

如何处理消息反应?

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

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

区别:

messageReactionAdd是一个与 相关联的事件Client

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

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

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

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

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

那么,我用什么?

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

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

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

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

注意:如果机器人重新启动,ReactionCollectorawaitReactions将被删除,而messageReactionAdd将照常工作(但您将丢失您声明的变量,因此如果您已存储要收听的消息,它们也会消失)。

该怎么办?

你需要不同的东西:

  • 将触发功能的表情符号列表(您可以选择对每个表情符号做出反应)
  • 停止收听消息反应的条件(如果您想收听每条消息,则不适用) messageReactionAdd
  • 接收消息并对其进行编辑的函数
  • 一个将返回布尔值的过滤器函数:true我想对这个表情符号做出反应,false我不想做出反应。此功能将基于表情符号列表,但也可以过滤用户的反应或您需要的任何其他条件
  • 编辑消息的逻辑。例如:对于列表,它将基于结果的数量,当前索引和添加的反应

示例:用户列表

表情符号列表:

const emojiNext = '?'; // unicode emoji are identified by the emoji itself
const emojiPrevious = '?';
const reactionArrow = [emojiPrevious, emojiNext];
Run Code Online (Sandbox Code Playgroud)

停止条件

const time = 60000; // time limit: 1 min
Run Code Online (Sandbox Code Playgroud)

编辑功能

这里的功能非常简单,消息是预先生成的(时间戳和页脚除外)。

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
}
Run Code Online (Sandbox Code Playgroud)

过滤功能

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
}
Run Code Online (Sandbox Code Playgroud)

逻辑

请注意,我在这里使用 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;
}
Run Code Online (Sandbox Code Playgroud)

这是另一个 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;
Run Code Online (Sandbox Code Playgroud)

构建构造函数

该示例与问题中的要求相同,使用箭头功能编辑消息。

我们将使用一个收集器:

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());
}
Run Code Online (Sandbox Code Playgroud)

它需要我们想听的信息。你也可以给它一个内容列表 // 消息 // 一个数据库 // 任何必要的东西。

发送消息并添加收集器

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));
}
Run Code Online (Sandbox Code Playgroud)