You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Discord.js 自定义Emoji反应角色功能失效问题

问题根因
  • 匹配逻辑错误:代码中直接将reaction.emoji(Emoji实例对象)和自定义的Emoji格式字符串做全等判断,二者数据类型不一致,判断条件永远不成立。内置Unicode Emoji能正常运行是JS隐式类型转换的巧合,自定义服务器Emoji是GuildEmoji实例,隐式转换无法匹配你定义的<:名称:ID>格式字符串,所以角色分配逻辑根本不会触发。
  • 监听器注册位置错误:将messageReactionAdd、messageReactionRemove事件监听写在命令的execute方法内,每次执行命令都会重复注册监听器,不仅会造成内存泄漏、重复触发加角色逻辑,机器人重启后如果没有重新执行命令,监听器会直接消失,功能完全失效。
  • 潜在缓存问题:直接用members.cache.get()取用户对象,若目标成员不在缓存中会返回null,后续调用角色添加/删除方法会直接报错。
修复步骤
  1. 调整Emoji匹配规则:自定义Emoji的ID是全局唯一标识,直接比对reaction.emoji.id和Emoji的ID即可,不需要匹配完整格式字符串。
  2. 迁移事件监听器:将两个反应相关的事件监听器移到机器人启动入口文件(即写有client.login()的index.js/app.js文件),保证机器人启动时只注册一次监听器。
  3. 替换成员获取逻辑:用异步的guild.members.fetch()方法获取成员实例,避免缓存缺失导致的报错。
  4. 检查Client配置:Discord.js v13+版本需要手动开启对应Intent并配置Partial,否则无法正常接收反应事件。
修复后代码

反应角色命令文件

module.exports = {
    name: 'reactionrole',
    description: "Sets up a reaction role message",
    async execute(message, args, Discord, client) {
        const channelId = '996702836249346119';
        const omegaRole = message.guild.roles.cache.find(role => role.name === "ω");
        const omega0Role = message.guild.roles.cache.find(role => role.name === "ω₀");
        const omega1Role = message.guild.roles.cache.find(role => role.name === "ω₁");

        // 单独存储Emoji ID用于匹配,拼接格式字符串用于消息展示、添加反应
        const omegaEmojiId = '996350040912183358';
        const omega0EmojiId = '996440594199089182';
        const omega1EmojiId = '996425564304986122';
        const omegaEmoji = `<:Waaa:${omegaEmojiId}>`;
        const omega0Emoji = `<a:fendi_fireyellow:${omega0EmojiId}>`;
        const omega1Emoji = `<:fendi_joeShush:${omega1EmojiId}>`;

        let embed = new Discord.MessageEmbed()
            .setColor('#e42643')
            .setTitle('-------------------- • 💛 ™       ')
            .setDescription('\n\n\n' +
                `${omegaEmoji} "- @ω"\n\n` +
                `${omega0Emoji} "- @ω₀"\n\n` +
                `${omega1Emoji} "- @ω₁"`);

        let messageEmbed = await message.channel.send(embed);
        messageEmbed.react(omegaEmoji);
        messageEmbed.react(omega0Emoji);
        messageEmbed.react(omega1Emoji);
    }
}

入口文件事件监听配置

// 反应角色对应规则配置
const REACTION_ROLE_RULES = {
    targetChannelId: '996702836249346119',
    emojiRoleMap: [
        { emojiId: '996350040912183358', roleName: 'ω' },
        { emojiId: '996440594199089182', roleName: 'ω₀' },
        { emojiId: '996425564304986122', roleName: 'ω₁' }
    ]
}

// 加反应分配角色
client.on('messageReactionAdd', async(reaction, user) => {
    if (reaction.message.partial) await reaction.message.fetch();
    if (reaction.partial) await reaction.fetch();
    if (user.bot) return;
    if (!reaction.message.guild) return;
    if (reaction.message.channel.id !== REACTION_ROLE_RULES.targetChannelId) return;

    const matchedRule = REACTION_ROLE_RULES.emojiRoleMap.find(rule => rule.emojiId === reaction.emoji.id);
    if (!matchedRule) return;

    const targetRole = reaction.message.guild.roles.cache.find(role => role.name === matchedRule.roleName);
    if (!targetRole) return;

    const member = await reaction.message.guild.members.fetch(user.id);
    await member.roles.add(targetRole);
});

// 移除反应收回角色
client.on('messageReactionRemove', async(reaction, user) => {
    if (reaction.message.partial) await reaction.message.fetch();
    if (reaction.partial) await reaction.fetch();
    if (user.bot) return;
    if (!reaction.message.guild) return;
    if (reaction.message.channel.id !== REACTION_ROLE_RULES.targetChannelId) return;

    const matchedRule = REACTION_ROLE_RULES.emojiRoleMap.find(rule => rule.emojiId === reaction.emoji.id);
    if (!matchedRule) return;

    const targetRole = reaction.message.guild.roles.cache.find(role => role.name === matchedRule.roleName);
    if (!targetRole) return;

    const member = await reaction.message.guild.members.fetch(user.id);
    await member.roles.remove(targetRole);
});

Client初始化必要配置(v13+版本)

const { Client, Intents } = require('discord.js');
const client = new Client({
    intents: [
        Intents.FLAGS.GUILDS,
        Intents.FLAGS.GUILD_MESSAGES,
        Intents.FLAGS.GUILD_MESSAGE_REACTIONS, // 必须开启才能接收消息反应事件
        Intents.FLAGS.GUILD_MEMBERS
    ],
    partials: ['MESSAGE', 'CHANNEL', 'REACTION', 'USER'] // 配置partial才能获取缓存外的消息、反应数据
});

内容的提问来源于stack exchange,提问作者Ruffo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 12:33:12