首页 > 解决方案 > 如何在 react 中应用 markdown-to-jsx 包中的代码高亮?

问题描述

我正在使用 markdown-to-jsx 包来在我的 react 项目中呈现文档内容。这个包提供了一个 Markdown 组件,它接受一个 options 属性来覆盖 HTML 元素的默认样式等等。

const markdownOptions = {
    wrapper: DocsContentWrapper, 
    forceWrapper: true,
    overrides: {
        h1: LeadTitle,
        h2: SecondaryTitle,
        h3: ThirdTitle,
        p: Paragraph, 
        pre: CodeWrapper,
        ol: ListWrapper,
        li: ListItem,
    },
};

<Markdown 
    options={MarkdownOptions}
>
    {MockDoc}
</Markdown>

现在,Markdown 组件接受了一个 markdown,所以我将一个按照 markdown规则格式化的字符串传递给它。

它包含一些代码块,如下所示,我想将颜色添加到:

在此处输入图像描述

我使用“react-syntax-highlighter”包创建了一个组件,它如下所示:

import React from 'react';

import { Prism as SyntaxHighlighter } from "react-syntax-highlighter"
import { tomorrow } from "react-syntax-highlighter/dist/esm/styles/prism"

const SyntaxHighligher = ({ language, markdown }) => {
    
    return (
        <SyntaxHighlighter 
            language={language} 
            style={tomorrow}
        >
            {markdown}
        </SyntaxHighlighter>
    );
};

export default SyntaxHighligher;

问题来了——我怎样才能将两者结合起来?我在想如果选项对象接受这样的配置是有意义的,但是通过他们的 GitHub 页面查看“markdown-to-jsx”文档,显示没有选项。

我已经看到一个名为“react-markdown”的包,它能够接受我的 SyntaxHighligher 组件和任务,但我想使用“markdown-to-jsx”包应用相同的功能。

标签: reactjsmarkdownjsxsyntax-highlighting

解决方案


markdown-to-jsx将代码块生成为<pre><code>...</code></pre>,但我们不能简单地覆盖code标记,因为内联代码也使用它。来自的自述文件markdown-to-jsx建议我们可以pre > code以某种方式覆盖:

一些元素映射与其他库有点不同,特别是:

span: 用于内嵌文本。
code: 用于内联代码。
pre > code: 代码块是一个以 pre 为直接祖先的代码元素。

但根据我的实验和对源代码的阅读,我认为唯一的方法是覆盖pre并检查codechildren. 例如:

import {Prism as SyntaxHighlighter} from 'react-syntax-highlighter';
import {materialDark as CodeStyle} from 'react-syntax-highlighter/dist/esm/styles/prism';

const CodeBlock = ({className, children}) => {
  let lang = 'text'; // default monospaced text
  if (className && className.startsWith('lang-')) {
    lang = className.replace('lang-', '');
  }
  return (
    <SyntaxHighlighter language={lang} style={CodeStyle}>
      {children}
    </SyntaxHighlighter>
  );
}

// markdown-to-jsx uses <pre><code/></pre> for code blocks.
const PreBlock = ({children, ...rest}) => {
  if ('type' in children && children ['type'] === 'code') {
    return CodeBlock(children['props']);
  }
  return <pre {...rest}>{children}</pre>;
};

const YourComponent = () => {
  return (
    <Markdown
      options={{
        overrides: {
          pre: PreBlock,
        },
      }}
    >
      {yourMarkdown}
    </Markdown>
  );
};

不幸的是,如果您想同时覆盖内联代码和代码块,我没有一个好的解决方案。当同时覆盖precode标签时,code生成的标签SyntaxHighlighter也会被覆盖,因此内联代码和代码块的呈现方式相同。


推荐阅读