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

如何让Discord.js机器人同时支持斜杠命令与前缀命令?

同时支持Discord斜杠命令与自定义前缀命令的实现方案

一、标准化命令文件结构

首先要让每个命令同时兼容两种调用方式,调整命令文件的结构,让execute函数能处理**消息对象(Message)和斜杠交互对象(ChatInputCommandInteraction)**两种场景:

const { SlashCommandBuilder } = require('discord.js');

module.exports = {
  // 斜杠命令的配置,同时作为前缀命令的基础信息
  data: new SlashCommandBuilder()
    .setName('ping')
    .setDescription('回复Pong!')
    .setDMPermission(true),
  // 前缀命令的别名(可选)
  aliases: ['p'],
  // 统一执行逻辑,自动判断调用类型
  async execute(context) {
    const isSlashCommand = context.isChatInputCommand();
    const replyContent = 'Pong!';

    if (isSlashCommand) {
      await context.reply(replyContent);
    } else {
      await context.channel.send(replyContent);
    }
  },
};

二、优化命令加载逻辑

重构原有加载代码,简化嵌套结构,同时单独收集斜杠命令的配置用于Discord平台注册:

const path = require('path');
const fs = require('fs');
const { Collection, SlashCommandBuilder } = require('discord.js');

module.exports = (client) => {
  client.commands = new Collection(); // 存储所有命令(含别名)
  client.slashCommands = []; // 存储斜杠命令的JSON配置,用于注册
  const foldersPath = path.join(__dirname, 'commands');
  const commandFolders = fs.readdirSync(foldersPath);

  for (const folder of commandFolders) {
    const commandsPath = path.join(foldersPath, folder);
    const commandFiles = fs.readdirSync(commandsPath).filter(file => file.endsWith('.js'));

    for (const file of commandFiles) {
      const filePath = path.join(commandsPath, file);
      try {
        const command = require(filePath);
        
        // 验证必要结构
        if (!(command.data instanceof SlashCommandBuilder) || typeof command.execute !== 'function') {
          console.log(`[WARNING] 命令文件 ${filePath} 缺少合法的data或execute方法`);
          continue;
        }

        // 注册主命令名
        client.commands.set(command.data.name, command);
        // 注册前缀命令别名
        if (command.aliases && Array.isArray(command.aliases)) {
          command.aliases.forEach(alias => {
            if (!client.commands.has(alias)) {
              client.commands.set(alias, command);
            } else {
              console.log(`[WARNING] 别名 ${alias} 已被占用,跳过注册`);
            }
          });
        }

        // 收集斜杠命令配置
        client.slashCommands.push(command.data.toJSON());
      } catch (err) {
        console.error(`[ERROR] 加载命令文件 ${filePath} 失败`, err);
      }
    }
  }
};

三、注册斜杠命令到Discord

创建单独的部署脚本(避免每次启动机器人都重复注册),将斜杠命令提交到Discord平台:

const { REST, Routes } = require('discord.js');
const config = require('./config.json'); // 你的配置文件,包含token和clientId
const loadCommands = require('./load-commands'); // 上面的命令加载函数
const client = require('./client'); // 你的机器人客户端实例

// 先加载命令,再执行注册
loadCommands(client);

const rest = new REST({ version: '10' }).setToken(config.token);

async function deploySlashCommands() {
  try {
    console.log(`开始注册 ${client.slashCommands.length} 个斜杠命令...`);

    // 全局注册(生效需1小时左右),测试服务器可添加guildId参数使用Routes.applicationGuildCommands
    const data = await rest.put(
      Routes.applicationCommands(config.clientId),
      { body: client.slashCommands },
    );

    console.log(`成功注册 ${data.length} 个斜杠命令`);
  } catch (error) {
    console.error(error);
  }
}

deploySlashCommands();

四、处理两种命令的调用事件

在机器人主文件中添加消息和交互的监听逻辑,分别触发对应命令:

1. 处理前缀命令(消息事件)

client.on('messageCreate', async (message) => {
  // 忽略机器人自身消息和非前缀开头的消息
  if (message.author.bot) return;
  // 获取服务器自定义前缀(这里示例用默认值,实际可从数据库/配置读取)
  const prefix = await getGuildPrefix(message.guildId) || ';';
  if (!message.content.startsWith(prefix)) return;

  // 拆分命令名和参数
  const args = message.content.slice(prefix.length).trim().split(/ +/);
  const commandName = args.shift().toLowerCase();

  const command = client.commands.get(commandName);
  if (!command) return;

  try {
    await command.execute(message);
  } catch (error) {
    console.error(error);
    await message.reply('执行命令时出错了!');
  }
});

// 示例:获取服务器前缀的函数,根据你的存储方式修改
async function getGuildPrefix(guildId) {
  // 比如从数据库查询,无数据则返回null
  return null;
}

2. 处理斜杠命令(交互事件)

client.on('interactionCreate', async (interaction) => {
  if (!interaction.isChatInputCommand()) return;

  const command = client.commands.get(interaction.commandName);
  if (!command) return;

  try {
    await command.execute(interaction);
  } catch (error) {
    console.error(error);
    await interaction.reply({ content: '执行命令时出错了!', ephemeral: true });
  }
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 10:33:10