react-markdown的使用

安装

github-remarkjs-markdown

npm i react-markdown

基本使用

  • 表格、代码高亮、数学公式等均不支持
import React from 'react'
import ReactMarkdown from 'react-markdown'
import ReactDom from 'react-dom'

const markdownData = `
    ### test header
`

<RactMarkdown>
    {markdownData}
</ReactMarkdown>


ReactDom.render(
    <ReactMarkdown># Hello, *world*!</ReactMarkdown>, 
    document.body
)

remark-gfm多功能

  • npm install remark-Gfm
  • 配置后,可使用表格、删除线、任务列表、引用等操作。
import React from 'react'
import ReactMarkdown from 'react-markdown'
import ReactDom from 'react-dom'
import remarkGfm from 'remark-gfm'

const markdown = `A paragraph with *emphasis* and **strong importance**.

> A block quote with ~strikethrough~ and a URL: https://reactjs.org.

* Lists
* [ ] todo
* [x] done

A table:

| a | b |
| - | - |
`

ReactDom.render(
  <ReactMarkdown children={markdown} remarkPlugins={[remarkGfm]} />,
  document.body
)

highlighter语法高亮

  • 结合react-syntax-highlighter使得代码拥有语法高亮
npm i react-syntax-highlighter

使用

import React from "react";
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 = `
~~~js
console.log('markdownData!')
~~~
`;
const code = ({ node, inline, className, children=[], ...props }) => {
  const match = /language-(\w+)/.exec(className || "");
  return !inline && match ? (
      <SyntaxHighlighter
        children={String(children).replace(/\n$/, '')}
        style={dark}
        language={match[1]}
        PreTag="div"
        {...props}
      />
    ) : (
      <code className={className} {...props}>
        {children}
      </code>
    )
};
    
const Index = () => {
  return (
    <ReactMarkdowncomponents={{code: code}}>
      {markdownData}
    </ReactMarkdown>
  );
};
export default Index

katex数学公式

  • npm install remark-math rehype-katex

// <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.13.13/dist/katex.min.css" integrity="sha384-RZU/ijkSsFbcmivfdRBQDtwuwVqK7GMOw6IMvKyeWL2K5UAlyp6WonmB8m7Jd0Hn" crossorigin="anonymous">

import React from 'react'
import ReactDom from 'react-dom'
import ReactMarkdown from 'react-markdown'
import remarkMath from 'remark-math'
import rehypeKatex from 'rehype-katex'
import "katex/dist/katex.css";

const markdown = ` L = \frac{1}{2} \rho v^2 S C_L`

ReactDom.render(
  <ReactMarkdown
    children={markdown}
    remarkPlugins={[remarkMath]}
    rehypePlugins={[rehypeKatex]}
  />,
  document.body
)

remark-toc目录生成

  • 用于自动生成markdown的目录,仅需要在开头使用## Table of Content,即可以自动生成。
  • npm install remark-toc
import React from 'react'
import ReactDom from 'react-dom'
import ReactMarkdown from 'react-markdown'
import remarkToc from 'remark-toc'

ReactDom.render(
  <ReactMarkdown
    children={markdown}
    remarkPlugins={[remarkToc]}
  />,
  document.body
)

rehype-raw HTML支持

  • npm install rehype-raw
import React from 'react'
import ReactDom from 'react-dom'
import ReactMarkdown from 'react-markdown'
import rehypeRaw from 'rehype-raw'

const input = `<div class="note">

Some *emphasis* and <strong>strong</strong>!

</div>`

ReactDom.render(
  <ReactMarkdown rehypePlugins={[rehypeRaw]} children={input} />,
  document.body
)

自定义映射样式

  • html 元素映射fn返回组件或元素
<ReactMarkdown
  components={{
    h1: 'h2',
    em: ({node, ...props}) => <i style={{color: 'red'}} {...props} />
    p: () => <p style={{color: 'red'}} {...props} />
  }}
/>

流程图\数学公式

npm i mermaid
npm i katex
  • 最终使用
import ReactMarkdown from 'react-markdown'

const markdownData = `
    ### test header
`

<RactMarkdown
    components={{
        code: SpecialCode
    }}
>
    {markdownData}
</ReactMarkdown>

思路就是通过classname不同,判断code的类型,markdown就将 ```xxx 解析到classname中,并给一个language-xxx的classname,再通过classname使用不同的渲染器即可实现,下面将code函数的代码单独抽离出来

import React, { 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";

// <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.13.13/dist/katex.min.css" integrity="sha384-RZU/ijkSsFbcmivfdRBQDtwuwVqK7GMOw6IMvKyeWL2K5UAlyp6WonmB8m7Jd0Hn" crossorigin="anonymous">


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

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

      if (typeof dt === "string") {
        return dt;
      }
      if (dt.props && dt.props.children) {
        return getCode(dt.props.children);
      }
      return false;
    })
    .filter(Boolean)
    .join("");
}

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

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

  const [transformCode, setTransformCode] = useState("");

  const codeType = useMemo(() => {
    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";
    }
  }, [code, className]);

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

    setTransformCode(svg);
  }, []);

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

    setTransformCode(strCode);
  }, []);

  useEffect(() => {
    if (codeType === "mermaid") {
      renderMermaid(code);
    } else if (codeType === "katex") {
      renderKatex(code);
    }
  }, [code, codeType]);

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

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

const SpecialCode = ({ inline, ...extra }: CodeProps) => {
  if (inline) return <RenderInline {...extra} />;

  return <RenderBlock {...extra} />;
};

export default SpecialCode;

扩展:markdown 编辑器

### 如何在 React 应用程序中使用 `react-markdown` 插件 #### 安装依赖项 为了能够在 React 项目中使用 `react-markdown`,首先需要安装该库以及其可能依赖的一些其他包。可以通过 npm 或 yarn 来完成这一步骤。 ```bash npm install react-markdown remark-gfm ``` 或者如果偏好使用 Yarn: ```bash yarn add react-markdown remark-gfm ``` 这里额外添加了 `remark-gfm` 支持 GitHub 风格的 Markdown (GFM),使得可以解析表格、删除线等特性[^1]。 #### 基本用法示例 下面是一个简单的例子来展示如何导入并渲染一段 Markdown 文本为 HTML: ```jsx import React from 'react'; import ReactMarkdown from 'react-markdown'; import gfm from 'remark-gfm'; function App() { const source = ` # Welcome to My Blog! This is an example of **bold text**, and here's how you create a list: - Item one - Item two `; return ( <div> <h2>Rendered Markdown:</h2> <ReactMarkdown children={source} remarkPlugins={[gfm]} /> </div> ); } export default App; ``` 这段代码展示了如何通过 props 将字符串形式的 Markdown 内容传递给 `<ReactMarkdown>` 组件,并利用 `remarkPlugins` 属性启用 GFM 解析支持。 #### 处理自定义组件与样式 有时希望对某些特定类型的 Markdown 元素应用特殊的处理方式或样式。这时可以通过传入一个对象作为 `components` 参数来自定义这些行为。 ```jsx const CustomComponent = ({ node, inline, className, ...props }) => { // 自定义逻辑... }; <ReactMarkdown components={{ p: CustomComponent }} />; ``` 此方法允许开发者完全控制每种标签对应的呈现效果,从而更好地融入应用程序的设计体系。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值