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

如何在React Markdown中渲染自定义短代码为组件?

嗨,我之前刚好碰到过一模一样的需求,其实React Markdown虽然官方文档没直接提自定义短代码的处理,但可以通过两种方式实现——一种是用自定义remark插件解析AST,另一种是预处理文本替换短代码。下面给你详细说说这两种方案:

方案一:自定义remark插件解析短代码(推荐,更安全)

这种方式是通过操作Markdown的抽象语法树(AST)来识别短代码,不会有XSS风险,适合用户提交的不可控内容场景。

步骤1:写一个自定义remark插件

这个插件会遍历AST里的文本节点,匹配[[ table product="mask" ]]这样的短代码,把它转换成自定义的AST节点:

import { visit } from 'unist-util-visit';

// 自定义remark插件,解析table类型的短代码
export function remarkTableShortcodes() {
  return (tree) => {
    // 遍历所有文本节点
    visit(tree, 'text', (node, index, parent) => {
      // 匹配[[ table ... ]]格式的短代码
      const shortcodeRegex = /\[\[ table (.*?) \]\]/g;
      let match;
      const newChildren = [];
      let lastTextIndex = 0;

      // 逐个处理匹配到的短代码
      while ((match = shortcodeRegex.exec(node.value)) !== null) {
        // 保留短代码前面的普通文本
        if (match.index > lastTextIndex) {
          newChildren.push({
            type: 'text',
            value: node.value.slice(lastTextIndex, match.index),
          });
        }

        // 解析短代码里的属性(比如product="mask")
        const attrsString = match[1];
        const attributes = {};
        const attrRegex = /(\w+)="([^"]+)"/g;
        let attrMatch;
        while ((attrMatch = attrRegex.exec(attrsString)) !== null) {
          attributes[attrMatch[1]] = attrMatch[2];
        }

        // 添加自定义AST节点,类型设为customTable
        newChildren.push({
          type: 'customTable',
          data: {
            hName: 'custom-table', // 对应后续映射的组件标识
            hProperties: attributes,
          },
          ...attributes,
        });

        lastTextIndex = match.index + match[0].length;
      }

      // 处理剩余的文本内容
      if (lastTextIndex < node.value.length) {
        newChildren.push({
          type: 'text',
          value: node.value.slice(lastTextIndex),
        });
      }

      // 如果有匹配到短代码,替换原文本节点为新的子节点数组
      if (newChildren.length > 0) {
        parent.children.splice(index, 1, ...newChildren);
      }
    });
  };
}

步骤2:在React Markdown中使用插件并映射组件

把插件加到remarkPlugins里,再通过components属性把自定义的AST节点映射到你的<Table />组件:

import ReactMarkdown from 'react-markdown';
import { remarkTableShortcodes } from './remarkTableShortcodes';
import Table from './Table'; // 你的自定义Table组件

function MarkdownContent({ markdown }) {
  return (
    <ReactMarkdown
      remarkPlugins={[remarkTableShortcodes]}
      components={{
        // 把custom-table节点映射到自定义Table组件
        'custom-table': (props) => <Table {...props} />,
      }}
    >
      {markdown}
    </ReactMarkdown>
  );
}
方案二:预处理Markdown文本(简单快速,适合可控内容)

如果你的Markdown内容是自己生成的、完全可控的,直接预处理文本把短代码替换成React组件标签会更省事,但要注意开启相关插件支持JSX解析:

步骤1:写预处理函数

把[[ table product="mask" ]]替换成React组件的JSX语法:

function replaceTableShortcodes(markdown) {
  // 正则匹配并替换短代码为<Table />组件
  return markdown.replace(
    /\[\[ table (.*?) \]\]/g,
    (_, attrs) => `<Table ${attrs} />`
  );
}

步骤2:配置React Markdown支持JSX解析

需要用到rehype-raw插件来解析原生HTML/JSX,同时通过components映射标签到你的组件:

import ReactMarkdown from 'react-markdown';
import rehypeRaw from 'rehype-raw';
import Table from './Table';

function MarkdownContent({ markdown }) {
  const processedMarkdown = replaceTableShortcodes(markdown);
  
  return (
    <ReactMarkdown
      rehypePlugins={[rehypeRaw]}
      components={{
        // 把<Table />标签映射到自定义组件
        Table: Table,
      }}
    >
      {processedMarkdown}
    </ReactMarkdown>
  );
}

小提示

  • 方案一更安全,适合用户提交的内容,因为是基于AST解析,不会执行恶意代码;
  • 方案二实现起来更快,但如果内容不可控,开启rehype-raw可能会有XSS风险,要谨慎使用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 06:42:47