拔个牙了酸二狗 發表於 2023-3-30 14:29:00

react-markdown的使用

<h1 id="react-markdown的使用">react-markdown的使用</h1>
<h3 id="安装">安装</h3>
<pre><code class="language-bash">npm i react-markdown
</code></pre>
<h3 id="基本使用">基本使用</h3>
<pre><code class="language-ts">import ReactMarkdown from 'react-markdown'

const markdownData = `
    ### test header
`

&lt;RactMarkdown&gt;
    {markdownData}
&lt;/ReactMarkdown&gt;
</code></pre>
<h3 id="结合react-syntax-highlighter使得代码拥有语法高亮">结合react-syntax-highlighter使得代码拥有语法高亮</h3>
<pre><code class="language-bash">npm i react-syntax-highlighter #安装react-syntax-highlighter
</code></pre>
<pre><code class="language-ts">import ReactMarkdown from 'react-markdown'
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'
import { coldarkCold } from 'react-syntax-highlighter/dist/esm/styles/prism'

const markdownData = `
    ### test header
`

&lt;RactMarkdown
    components={{
      code: ({ children = [], className, ...props }) =&gt; {
            const match = /language-(\w+)/.exec(className || '')
            return (&lt;SyntaxHighlighter
                  language={match?.}
                  showLineNumbers={true}
                  style={coldarkCold as any}
                  PreTag='div'
                  className='syntax-hight-wrapper'
                  {...props}
                  &gt;
                  {children as string[]}
                  &lt;/SyntaxHighlighter&gt;)
      }
    }}
&gt;
    {markdownData}
&lt;/ReactMarkdown&gt;
</code></pre>
<h3 id="结合mermaid可以显示流程图和katex可以显示数学公式">结合mermaid(可以显示流程图)和katex(可以显示数学公式)</h3>
<p>思路就是通过classname不同,判断code的类型,markdown就将 ```xxx 解析到classname中,并给一个language-xxx的classname,再通过classname使用不同的渲染器即可实现,下面将code函数的代码单独抽离出来</p>
<pre><code class="language-ts">import { useRef, useEffect, useMemo, useCallback, useState } from 'react'
import { CodeProps } from 'react-markdown/lib/ast-to-react'
import mermaid from 'mermaid'
import katex from 'katex'
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'
import { coldarkCold } from 'react-syntax-highlighter/dist/esm/styles/prism'
import 'katex/dist/katex.css'

export default function SpecialCode({ inline, ...extra }: CodeProps) {
if (inline) return &lt;RenderInline {...extra} /&gt;

return &lt;RenderBlock {...extra} /&gt;
}

function RenderInline({ children = [] }: Omit&lt;CodeProps, 'inline'&gt;) {
const txt = children || ''
if (typeof txt === 'string' &amp;&amp; /^\$\$(.*)\$\$/.test(txt)) {
    const html = katex.renderToString(txt.replace(/^\$\$(.*)\$\$/, '$1'), { throwOnError: false })
    return (
      &lt;code
      style={{ backgroundColor: 'rgb(227, 234, 242)', padding: '0.2rem', borderRadius: '0.2rem' }}
      dangerouslySetInnerHTML={{ __html: html }}
      /&gt;
    )
}
return &lt;code&gt;{txt}&lt;/code&gt;
}

function RenderBlock({ children = [], className, ...props }: Omit&lt;CodeProps, 'inline'&gt;) {
const markId = useRef(`mark${randomId()}`)
const code = getCode(children)

const = useState('')

const codeType = useMemo(() =&gt; {
    if (typeof code !== "string" || typeof className !== "string") return

    if (/^language-mermaid/.test(className.toLocaleLowerCase())) {
      return 'mermaid'
    } else if (/^language-katex/.test(className.toLocaleLowerCase())) {
      return 'katex'
    }
}, )

const renderMermaid = useCallback(async (code: string) =&gt; {
    const { svg } = await mermaid.render(markId.current, code)

    setTransformCode(svg)
}, [])

const renderKatex = useCallback(async (code: string) =&gt; {
    const strCode = katex.renderToString(code, { throwOnError: false })

    setTransformCode(strCode)
}, [])

useEffect(() =&gt; {
    if (codeType === 'mermaid') {
      renderMermaid(code)
    } else if (codeType === 'katex') {
      renderKatex(code)
    }
}, )

if (codeType === 'mermaid') {
    return (
      &lt;div className='code-block' style={{ textAlign: 'center' }}&gt;
      &lt;code dangerouslySetInnerHTML={{ __html: transformCode }} /&gt;
      &lt;/div&gt;
    )
} else if (codeType === 'katex') {
    return (
      &lt;code
      className='code-block'
      dangerouslySetInnerHTML={{ __html: transformCode }}
      /&gt;
    )
}

const match = /language-(\w+)/.exec(className || '')
return &lt;SyntaxHighlighter
    language={match?.}
    showLineNumbers={true}
    style={coldarkCold as any}
    PreTag='div'
    className='syntax-hight-wrapper'
    {...props}
&gt;
    {children as string[]}
&lt;/SyntaxHighlighter&gt;
}

function randomId() {
return parseInt(String(Math.random() * 1e15), 10).toString(36)
}

function getCode(arr: React.ReactNode[] = []): string {
return arr.map((_dt) =&gt; {
    const dt = _dt as any

    if (typeof dt === "string") {
      return dt
    }
    if (dt.props &amp;&amp; dt.props.children) {
      return getCode(dt.props.children)
    }
    return false
}).filter(Boolean).join("")
}
</code></pre>
<p>再修改ReactMarkdown的代码如下</p>
<pre><code class="language-ts">import ReactMarkdown from 'react-markdown'

const markdownData = `
    ### test header
`

&lt;RactMarkdown
    components={{
      code: SpecialCode
    }}
&gt;
    {markdownData}
&lt;/ReactMarkdown&gt;
</code></pre><br><br>
来源:https://www.cnblogs.com/mbbk/p/react-markdown.html
頁: [1]
查看完整版本: react-markdown的使用