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

Discord机器人按钮功能报错:discord.ui无ActionRow属性

问题解决:Discord机器人取消钉选消息时按钮组件报错

错误原因

  1. 参数使用错误:你在发送消息时用了components参数,这是第三方库discord-components的语法,而原生discord.py 2.x发送组件应该使用view参数。
  2. 组件结构错误:虽然discord.ui.ActionRow存在,但原生discord.py推荐用discord.ui.View来管理交互组件,直接实例化ActionRow的写法不符合当前版本的最佳实践,且容易引发属性识别问题。
  3. 回调逻辑不符合需求:你的按钮回调是重发消息内容,而需求是跳转至原消息,应该使用URL类型按钮,无需自定义回调。

修正后的代码

核心功能代码

@bot.event
async def on_raw_reaction_remove(payload):
    if payload.emoji.name == "📌":
        channel = await bot.fetch_channel(payload.channel_id)
        message = await channel.fetch_message(payload.message_id)
        # 检查是否还有📌表情反应
        has_pin_reaction = any(str(reaction.emoji) == "📌" for reaction in message.reactions)
        if not has_pin_reaction:
            await message.unpin()
            # 生成原消息的跳转链接
            message_url = f"https://discord.com/channels/{payload.guild_id}/{payload.channel_id}/{payload.message_id}"
            # 创建链接类型按钮
            button = discord.ui.Button(
                label="查看被取消钉选的消息",
                style=discord.ButtonStyle.link,
                url=message_url
            )
            # 创建View容器并添加按钮
            view = discord.ui.View()
            view.add_item(button)
            # 发送带按钮的提示消息
            await channel.send("一条已钉选的消息被取消钉选。", view=view)
    print("Reaction removed.")

完整代码

import discord
from discord.ext import commands

intents = discord.Intents.all()
bot = commands.Bot(command_prefix='!', intents=intents)

THRESHOLD = 5

@bot.event
async def on_ready():
    channel = bot.get_channel(1069346031281651843)
    # 注释的公告代码保留原样
    print('All systems go!'.format(bot))

# 钉选消息功能
@bot.event
async def on_raw_reaction_add(payload):
    if payload.emoji.name == "📌":
        channel = await bot.fetch_channel(payload.channel_id)
        message = await channel.fetch_message(payload.message_id)
        await message.pin()
    print("Reaction added.")

# 取消钉选消息功能(修正后)
@bot.event
async def on_raw_reaction_remove(payload):
    if payload.emoji.name == "📌":
        channel = await bot.fetch_channel(payload.channel_id)
        message = await channel.fetch_message(payload.message_id)
        has_pin_reaction = any(str(reaction.emoji) == "📌" for reaction in message.reactions)
        if not has_pin_reaction:
            await message.unpin()
            message_url = f"https://discord.com/channels/{payload.guild_id}/{payload.channel_id}/{payload.message_id}"
            button = discord.ui.Button(
                label="查看被取消钉选的消息",
                style=discord.ButtonStyle.link,
                url=message_url
            )
            view = discord.ui.View()
            view.add_item(button)
            await channel.send("一条已钉选的消息被取消钉选。", view=view)
    print("Reaction removed.")

bot.run('你的TOKEN')

关键修改说明

  1. 替换组件发送方式:用view=view替代components=[...],符合discord.py原生组件系统的要求。
  2. 改用链接按钮:使用discord.ButtonStyle.link类型按钮,直接生成原消息的跳转链接,无需编写回调函数,既满足需求又避免交互逻辑错误。
  3. 简化反应检查逻辑:用any()替代列表推导式+长度判断,代码更简洁高效。
  4. 移除无效的ActionRow:使用discord.ui.View管理按钮,这是discord.py 2.x推荐的组件管理方式。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 03:53:15