如何制作一个从 .json 文件加载其元素的嵌入反应菜单?

Posted

技术标签:

【中文标题】如何制作一个从 .json 文件加载其元素的嵌入反应菜单?【英文标题】:How to make an embed reactions menu which loads its elements from a .json file? 【发布时间】:2019-10-29 23:51:09 【问题描述】:

我正在尝试制作一个菜单来显示我的公会自定义表情符号列表(请参阅 图片)。

我有一个 .json 文件,其中存储了表情符号和表情符号代码,我正在使用它来获得将来存储更多表情符号的能力。

这是我用来嵌入的代码:

execute(message) 
        const Discord = require('discord.js');
        const Emojis = require('./emojis.json');
        const keys = Object.keys(Emojis);
        var i = 0
        const embed = 
            "title": "Server emojis list:",
            "color": 1056085,
            "timestamp": new Date(),
            "footer": 
                "icon_url": "https://cdn.discordapp.com/icons/469276415746113568/f86e89f362f1df6dc1f996818ef49e7a.png?size=1024",
                "text": "Dz Gamers Community"
            ,
            "fields": [
                "name": "Emoji:",
                "value": `$Emojis[keys[i+0]]\n$Emojis[keys[i+1]]\n$Emojis[keys[i+2]]\n$Emojis[keys[i+3]]\n$Emojis[keys[i+4]]\n`,
                "inline": true
            , 
                "name": "Emoji code:",
                "value": `**$keys[i+0]\n$keys[i+1]\n$keys[i+2]\n$keys[i+3]\n$keys[i+4]\n**`,
                "inline": true
            ]
        ;

我正在为此使用反应收集器,但我不确定如何编辑嵌入字段。

message.channel.send(embed)
    .then(async embedMessage => 
        await embedMessage.react('◀')
        await embedMessage.react('▶')
        const emoji = 
            NEXT_PAGE: '▶',
            PREV_PAGE: '◀',
        
        const collector = new Discord.ReactionCollector(embedMessage, (reaction, user) => Object.values(emoji).includes(reaction.emoji.name) && !user.bot, );
        collector.on('collect', (reaction, user) => 
            switch (reaction.emoji.name) 
                case emoji.NEXT_PAGE:
                    
                        //Edit embed here (Next page)
                        embedMessage.reactions.get(emoji.PREV_PAGE).remove(message.author)
                        break;
                    
                case emoji.PREV_PAGE:
                    
                        //Edit embed here (Previous page)
                        embedMessage.reactions.get(emoji.PREV_PAGE).remove(message.author)
                        break;
                    
            ;
        );
        collector.on('end', () => embedMessage.delete());
    )

所以现在,我想要一种方法让机器人编辑嵌入,在每个菜单页面上加载 5 个表情符号(按顺序),所以我认为它应该是一个 var,var 值将是页码,然后我就可以使用keys[]

【问题讨论】:

【参考方案1】:

您可以创建一个简洁的小函数来帮助您解决这个问题。它将遍历您的 json 文件的条目,并将指定页面上所需的条目添加到嵌入中。然后,它会收集反应,并再次调用自己以显示不同的页面。

这更容易用一个例子来展示。确保在复制和粘贴代码之前理解代码。

// Require json file.
const emojis = require('./emojis.json');

// Define our function.
async function list(listMsg, page, increment) 
  const entries = Object.entries(emojis);

  // Set up base embed.
  var embed = new Discord.RichEmbed()
    .setColor(1056085)
    .setTitle('**Server Emojis**')
    .setDescription(`Page **$page** of $Math.ceil(entries.length/increment)`)
    .setFooter('Dz Gamers Community', 'https://cdn.discordapp.com/icons/469276415746113568/f86e89f362f1df6dc1f996818ef49e7a.png?size=1024')
    .setTimestamp(listMsg ? listMsg.createdAt : undefined);

  // Add fields to embed.
  const emojiField = [];
  const stringField = [];

  for (let [emoji, string] of entries.slice((page - 1) * increment, (page * increment) + 1)) 
    emojiField.push(emoji);
    stringField.push(string);
  

  embed.addField('Emoji:', emojiField.join('\n'), true);
  embed.addField('String:', stringField.join('\n'), true);

  // Edit/send embed.
  if (listMsg) await listMsg.edit(embed);
  else listMsg = await message.channel.send(embed);

  // Set up page reactions.
  const lFilter = (reaction, user) => reaction.emoji.name === '◀' && page !== 1 && user.id === message.author.id;
  const lCollector = listMsg.createReactionCollector(lFilter,  max: 1 );

  lCollector.on('collect', async () => 
    rCollector.stop();
    await listMsg.clearReactions();
    list(listMsg, page - 1, increment);
  );

  const rFilter = (reaction, user) => reaction.emoji.name === '▶' && entries.length > page * increment && user.id === message.author.id;
  const rCollector = listMsg.createReactionCollector(rFilter,  max: 1 );

  rCollector.on('collect', async () => 
    lCollector.stop();
    await listMsg.clearReactions();
    list(listMsg, page + 1, increment);
  );

  if (page !== 1) await listMsg.react('◀');
  if (entries.length > page * increment) await listMsg.react('▶');


// Send the list; page 1, and 5 shown on each page.
list(undefined, 1, 5)
  .catch(console.error);

由于某些部分可能看起来令人困惑且难以理解,因此这里有一些进一步的解释:

Math.ceil(entries.length / increment)entries 的长度除以每页上显示的元素数量 (increment) 将得出总共应该​​有多少页。我们ceil它,因为如果还有剩余,我们需要另一个页面。 embed.setTimestamp(listMsg ? listMsg.createdAt : undefined) 如果我们在每次编辑消息时设置嵌入的时间戳,那么它不是发送消息的时间。因此,如果我们正在编辑一条消息,我们将其设置为该消息的时间戳;如果我们要发送一个新的时间戳,我们会使用一个新的时间戳(RichEmbed.setTimestamp() 在没有提供值时使用当前时间)。 const [emoji, string] of entries.slice(...) [emoji, string] 提取条目的键和值并分别赋值。 entries.slice((page - 1) * increment, (page * increment) + 1) (page - 1) * increment 是切片的起始索引。 page 不是从零开始的,所以我们必须从中减去一。然后,我们将其乘以应在每个页面上显示的元素数量,因为所有这些元素都已显示。 (page * increment) + 1 是要切片的结束索引。这次我们不会从page 中减去,因为这会回到起点——increment 元素已经显示。我们必须向它添加一个,因为end 索引处的元素不包含在Array.slice() 中。 entries.length > page * increment 我们可以通过测试entries的长度是否比显示的最后一个元素的位置长来检查是否还有更多条目。

【讨论】:

我需要一些时间来了解代码的功能。目前,当您做出反应 ◀ 以返回上一页时,会出现此 problem。 您使用的是准确的代码吗?看起来好像机器人正在触发自己的收集器,但过滤器应该阻止这种情况。我注意到表情符号和字符串字段已为您翻转。如果您希望反映您的 json 设置,可以重命名它们。 是的,我使用的是相同的代码,我也注意到了这一点。我认为我的连接造成了一些延迟。 如何让它只显示5个表情符号,现在显示6个,我应该改变什么? 我在代码中发现了错误——收集器没有停止,所以创建了重复项。使用编辑后的版本。至于emoji的数量,你可以改变函数的最后一个参数。

以上是关于如何制作一个从 .json 文件加载其元素的嵌入反应菜单?的主要内容,如果未能解决你的问题,请参考以下文章

WPF - Json.NET:如何从 Json 反序列化多个对象并将其放入列表中?

从嵌入式 soundcloud 元素中获取声音数据

如何反编译旧Macromedia Director 7制作的可执行文件?

嵌入式linux与物联网进阶之路三:根文件系统制作

如何加载 JSON 文件并将其转换为特定类型的对象?

我该如何制作它,以便我可以调用嵌入到另一个文件并将其发布?