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

如何在ReactMarkdown中处理{{...}}格式的自定义标签?

在ReactMarkdown中支持{{...}}自定义标签的解决方案

要实现将{{cars:audi:q7}}这类自定义标签转换为指定HTML元素,你可以基于remark生态编写自定义插件,结合ReactMarkdown的components配置来完成,具体步骤如下:

1. 编写自定义remark插件解析标签

这个插件会遍历markdown文本中的所有文本节点,识别{{...}}格式的标签,将其转换为自定义的AST节点,同时保留前后的普通文本。

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

export function remarkCustomTags() {
  return (tree) => {
    // 匹配{{开头、}}结尾的标签,捕获中间内容
    const tagPattern = /{{([^}]+)}}/g;

    visit(tree, 'text', (node, index, parent) => {
      const rawText = node.value;
      let matchResult;
      const newNodes = [];
      let lastPosition = 0;

      // 遍历所有匹配到的标签
      while ((matchResult = tagPattern.exec(rawText)) !== null) {
        const [fullTag, tagContent] = matchResult;
        const tagStart = matchResult.index;
        const tagEnd = tagStart + fullTag.length;

        // 提取标签前的普通文本,转为文本节点
        if (tagStart > lastPosition) {
          newNodes.push({
            type: 'text',
            value: rawText.slice(lastPosition, tagStart)
          });
        }

        // 拆分标签内容(按:分隔)
        const tagParts = tagContent.split(':');
        // 生成自定义AST节点,携带标签参数
        newNodes.push({
          type: 'customTag',
          data: {
            hName: 'custom-tag', // 用于后续React组件映射的标识
            hProperties: { parts: tagParts }
          },
          parts: tagParts
        });

        lastPosition = tagEnd;
      }

      // 处理标签后的剩余文本
      if (lastPosition < rawText.length) {
        newNodes.push({
          type: 'text',
          value: rawText.slice(lastPosition)
        });
      }

      // 替换原文本节点为新的节点数组
      if (newNodes.length > 0) {
        parent.children.splice(index, 1, ...newNodes);
      }
    });
  };
}

2. 在ReactMarkdown中配置插件与自定义组件

将上述插件传入ReactMarkdown的remarkPlugins,并通过components属性将自定义AST节点映射为React组件,实现标签到目标HTML的转换。

import ReactMarkdown from 'react-markdown';
import { remarkCustomTags } from './remarkCustomTags';

// 自定义标签渲染组件
const CustomTagRenderer = ({ parts }) => {
  const [tagType, ...params] = parts;
  
  // 处理cars类型的标签
  if (tagType === 'cars') {
    const [make, model] = params;
    return (
      <a href={`mysite.com/cars?make=${make}&model=${model}`}>
        some text
      </a>
    );
  }

  // 其他类型标签的处理逻辑可以在这里扩展
  // 如果是未定义的标签,返回原始文本
  return <span>{`{{${parts.join(':')}}}`}</span>;
};

// 封装渲染组件
function MarkdownWithCustomTags({ content }) {
  return (
    <ReactMarkdown
      remarkPlugins={[remarkCustomTags]}
      components={{
        'custom-tag': CustomTagRenderer // 对应插件中hName的标识
      }}
    >
      {content}
    </ReactMarkdown>
  );
}

// 使用示例
const demoContent = 'This is my favorite car {{cars:audi:q7}} this year.';
<MarkdownWithCustomTags content={demoContent} />;

扩展说明

  • 如果你的标签格式更复杂(比如包含空格、嵌套逻辑),可以调整正则表达式和标签内容的解析逻辑;
  • 可以在CustomTagRenderer中添加更多标签类型的处理分支,支持多种自定义标签需求;
  • 若需要对标签参数做转义处理(比如URL编码),可以在组件中添加encodeURIComponent等逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 13:50:29