import React, { memo, useMemo } from 'react'; import ReactMarkdown from 'react-markdown'; import { copyToClipboard } from '../utils/clipboard'; import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'; import { oneDark } from 'react-syntax-highlighter/dist/esm/styles/prism'; import remarkGfm from 'remark-gfm'; import remarkMath from 'remark-math'; import rehypeKatex from 'rehype-katex'; import 'katex/dist/katex.min.css'; // KaTeX 样式 interface MarkdownRendererProps { content: string; className?: string; isStreaming?: boolean; // 是否正在流式输出 } const MarkdownRenderer: React.FC = memo(({ content, className = '', isStreaming = false }) => { // 流式输出时使用简化渲染,完成后才做完整 Markdown 渲染 const remarkPlugins = useMemo(() => isStreaming ? [] : [remarkGfm, remarkMath], [isStreaming]); const rehypePlugins = useMemo(() => isStreaming ? [] : [rehypeKatex], [isStreaming]); // 缓存 components 配置,避免每次渲染都创建新对象 const components = useMemo(() => ({ // 代码块渲染 - 流式时简化处理 code({ inline, className, children, ...props }: any) { const match = /language-(\w+)/.exec(className || ''); const language = match ? match[1] : ''; // 流式输出时使用简单代码块,避免频繁高亮计算 if (isStreaming && !inline && language) { return (
            {children}
          
); } return !inline && language ? (
{String(children).replace(/\n$/, '')}
) : ( {children} ); }, // 表格样式 table({ children }: any) { return (
{children}
); }, thead({ children }: any) { return ( {children} ); }, th({ children }: any) { return ( {children} ); }, td({ children }: any) { return ( {children} ); }, // 标题样式 h1({ children }: any) { return (

{children}

); }, h2({ children }: any) { return (

{children}

); }, h3({ children }: any) { return (

{children}

); }, h4({ children }: any) { return (

{children}

); }, // 段落样式 p({ children }: any) { return (

{children}

); }, // 列表样式 ul({ children }: any) { return ( ); }, ol({ children }: any) { return (
    {children}
); }, li({ children }: any) { return (
  • {children}
  • ); }, // 引用样式 blockquote({ children }: any) { return (
    {children}
    ); }, // 链接样式 a({ href, children }: any) { return ( {children} ); }, // 强调样式 strong({ children }: any) { return ( {children} ); }, em({ children }: any) { return ( {children} ); }, // 分割线 hr() { return (
    ); }, }), [isStreaming]); return (
    {content}
    ); }); export default MarkdownRenderer;