示例和程式碼
前言
react-markdown 是一款非常優秀的 markdown 轉 html 的 react 元件,但是官方文件是全英文而且也沒有說明的太詳細,我就把自己開發遇到的問題以及總結記錄下來,希望幫助更多的開發人員。
安裝和使用
安裝
npm install --save react-markdown
yarn add react-markdown
基本使用
const React = require('react')
const ReactDOM = require('react-dom')
const ReactMarkdown = require('react-markdown')
const input = '# This is a header\n\nAnd this is a paragraph'
ReactDOM.render(<ReactMarkdown source={input} />, document.getElementById('container'))
這裡有個問題 source 屬性是直接設定成 input 字串,當然如果你想記錄的文字不多倒還好,如果你是想做成文件形式那麼設定成字串顯然不好,正確的操作應該是獲取.md 檔案內容給source屬性,下面我們就來講如何操作。
react-markdown source 屬性從 .md 檔案中獲取內容
配置webpack
在使用之前我們要設定 webpack 支援.md 檔案,要不然直接引入會報錯,程式碼如下:
npm install -D raw-loader
yarn add -D raw-loader
rules: [
{
test: /\.md$/,
use: "raw-loader"
},
...
這樣設定好之後就可以了,然後我們就可以直接引入.md 檔案做為 source 屬性了,是不是非常方便!
api.md
## API
### PreviewLayout
| 引數 | 說明 | 型別 | 預設值 | 版本 |
| :------- | :------------------------- | :--: | :----: | :---: |
| children | 傳遞的元件,可以是任意元件 | jsx | null | 0.1.0 |
### MdPreviewer
| 引數 | 說明 | 型別 | 預設值 | 版本 |
| :--- | :------------ | :----: | :----: | :---: |
| md | markdown 文件 | string | null | 0.1.0 |
### CodePreviewer
| 引數 | 說明 | 型別 | 預設值 | 版本 |
| :------- | :------------- | :----: | :----: | :---: |
| code | 要顯示的程式碼 | string | null | 0.0.1 |
| showCode | 是否要展示程式碼 | bool | true | 0.1.0 |
import apiMd from "../md/api.md";
<ReactMarkdown
source={apiMd}
escapeHtml={false}
renderers={{
code: CodeBlock,
heading: HeadingBlock
}}
/>
執行看看
SyntaxHighlighter 設定語法高亮
react-markdown 預設設定程式碼只有個灰色背景,並沒有對語法進行高亮設定,我們可以根據它提供的Node types 的 code 屬性進行自定義語法高亮,這裡我們要引入SyntaxHighlighter包。
npm install react-syntax-highlighter
yarn add react-syntax-highlighter
然後,新建一個CodeBlock.js 檔案
import React, { PureComponent } from "react";
import PropTypes from "prop-types";
import { PrismLight as SyntaxHighlighter } from "react-syntax-highlighter";
// 設定高亮樣式
import { coy } from "react-syntax-highlighter/dist/esm/styles/prism";
// 設定高亮的語言
import { jsx, javascript, sass, scss } from "react-syntax-highlighter/dist/esm/languages/prism";
class CodeBlock extends PureComponent {
static propTypes = {
value: PropTypes.string.isRequired,
language: PropTypes.string
};
static defaultProps = {
language: null
};
componentWillMount() {
// 註冊要高亮的語法,
// 注意:如果不設定打包後供第三方使用是不起作用的
SyntaxHighlighter.registerLanguage("jsx", jsx);
SyntaxHighlighter.registerLanguage("javascript", javascript);
}
render() {
const { language, value } = this.props;
return (
<figure className="highlight">
<SyntaxHighlighter language={language} style={coy}>
{value}
</SyntaxHighlighter>
</figure>
);
}
}
export default CodeBlock;
這裡有三點要說明一下:
- 設定語法高亮的語言
import { jsx, javascript, sass, scss } from "react-syntax-highlighter/dist/esm/languages/prism";
node_modules/react-syntax-highlighter/dist/esm/languages/prism下有好多語言提供選擇,你們可以自己按照自己的意思挑選要引入的語言,上面是我引入的語言。
- 註冊你的語言
上面我們引入了語言包,我們還要註冊一下,如果不註冊的話,有可能打包後的高亮不起作用,以防萬一我們把需要的語言都註冊下。
SyntaxHighlighter.registerLanguage("jsx", jsx);
SyntaxHighlighter.registerLanguage("javascript", javascript);
- 設定語法高亮樣式
import { coy } from "react-syntax-highlighter/dist/esm/styles/prism";
node_modules/react-syntax-highlighter/dist/esm/styles/prism下有好多樣式提供選擇,我選擇的是 coy,你們可以自己一個個試試挑選自己喜歡的語法高亮顏色。
下面我們再看看這段程式碼
render() {
const { language, value } = this.props;
return (
<figure className="highlight">
<SyntaxHighlighter language={language} style={coy}>
{value}
</SyntaxHighlighter>
</figure>
);
}
透過從 props 獲取要設定的語言 language,程式碼 value,樣式從本地設定為 coy,那麼父元件裡面我們這樣設定:
import CodeBlock from "../CodeBlock";
import codePreviewMd from "../md/codePreviewer.md";
<ReactMarkdown
source={codePreviewMd}
escapeHtml={false}
renderers={{
code: CodeBlock,
heading: HeadingBlock
}}
/>
那麼我們 codePreviewer.md 檔案裡面就可以這樣設定程式碼
codePreviewer.md
<div>
<section></section>
</div>
import { PreviewLayout } from "react-code-previewer";
<PreviewLayout></PreviewLayout>;
上面的 html & code 和 jsx & code 就會透過 code:CodeBlock 以 language 和 value傳入到CodeBlock。
設定 <h123456 標題anchor 錨點功能
透過發現我們知道 github 的 markdown 的 README.md 文件是有錨點功能的,我們現在使用的 react-markdown是沒有這個功能的,那麼我們只能自定義了,好在 react-markdown 為我們提供了重寫 h 標籤的屬性:heading,下面我們來看看如何設定。
什麼是錨點?
使用命名錨記可以在文件中設定標記,這些標記通常放在文件的特定主題處或頂部。然後可以建立到這些命名錨記的連結,這些連結可快速將訪問者帶到指定位置。
所以錨點功能包含兩個部分:id 標記(或者 name 標記) 和 定位錨點的連結 兩部分構成,如下是我設定 h 標籤錨點的程式碼:
<h1 id='h1-anchor-id'>
<span>{children}</span>
<a href='#h1-anchor-id'>#</a>
</h1>
點選 a 標籤就可以定位到 id=’h1-anchor-id’的h1。這裡有個問題就是我的標題可能是 h1-h6 我不可能每次都自己寫 上面的程式碼如
<h2 id='h1-anchor-id'>
<span>{children}</span>
<a href='#h1-anchor-id'>#</a>
</h2>
<h3 id='h1-anchor-id'>
<span>{children}</span>
<a href='#h1-anchor-id'>#</a>
</h3>
這顯然程式碼有點冗餘了,我們只有自己寫個公共的方法去設定 h1-h6,我們建立一個 Heading.js檔案
Heading.js
import React from "react";
const elements = {
h1: "h1",
h2: "h2",
h3: "h3",
h4: "h4",
h5: "h5",
h6: "h6"
};
function Heading({ level, children, ...props }) {
return React.createElement(elements[level] || elements.h1, props, children);
}
Heading.defaultProps = {
type: "h1"
};
export default Heading;
這樣我透過你傳遞進來的 level屬性決定使用 h1-h6 中的某個標題了。
接下來我們建立HeadingBlock.js 檔案
HeadingBlock.js
import React, { PureComponent } from "react";
import PropTypes from "prop-types";
import cls from "classnames";
import Heading from "./Heading";
class HeadingBlock extends PureComponent {
renderHtml = () => {
const { level, children } = this.props;
if (children && children.length > 0) {
const nodeValue = children[0].props.value;
return (
<Heading level={`h${level}`} id={nodeValue}>
<span className="title">{children}</span>
<a href={`#${nodeValue}`} className="link">
#
</a>
</Heading>
);
} else {
return <>{children}</>;
}
};
render() {
return <>{this.renderHtml()}</>;
}
}
export default HeadingBlock;
如上面程式碼所示,我們透過父元件傳遞進來的 level:就是 1-6 數值, children:標題內容,如 level:2,children:’這是標題內容’,其實就是 markdown 裡的:## 這是標題內容。這樣就把 level 傳遞到 Heading元件就可選用你設定的 h 了,這樣錨點功能就設定完畢,我們再來看看父元件程式碼如何設定
import CodeBlock from "CodeBlock";
import HeadingBlock from "HeadingBlock";
import codePreviewMd from "../md/codePreviewer.md";
<ReactMarkdown
source={codePreviewMd}
escapeHtml={false}
renderers={{
code: CodeBlock,
heading: HeadingBlock
}}
/>
總結
1、react-markdown 解決了我們渲染 markdown檔案樣式和語法高亮問題
2、react-syntax-highlighter 解決我們渲染 markdown 語法高亮問題,其實它可以單獨使用的,具體的請檢視官方文件
3、react-syntax-highlighter設定的語言要註冊一下,如:SyntaxHighlighter.registerLanguage("jsx", jsx);
否則可能不起作用
4、react-markdown 提供了好多替代方案都包含在 Node Types 裡面
本作品採用《CC 協議》,轉載必須註明作者和本文連結