仿Github的markdown渲染效果
2020-06-19 本文已影响0人
percykuang
安装依赖
-
添加markdown渲染
yarn add react-markdown
-
实现代码高亮
yarn add highlight.js
-
使用styled-components进行UI组件封装
yarn add styled-components
yarn add --dev @types/styled-components
CodeBlock组件
// index.css
code {
font-family: "SFMono-Regular", "Consolas", "Liberation Mono", "Menlo", "monospace";
border-radius: 3px;
background-color: rgba(27,31,35,.05);
}
import React, { useEffect } from 'react'
import highLight from 'highlight.js'
// 主题文件:github、github-gist、color-brewer、railscasts、agate、atom-one-dark、rainbow、atom-one-light
import 'highlight.js/styles/github-gist.css' //代码块样式
import './index.css'
interface IProps {
value: string
language: string
}
export default function (props: IProps) {
const ref = React.createRef<HTMLElement>()
useEffect(() => {
if (ref.current) {
highLight.highlightBlock(ref.current)
}
})
return (
<pre>
<code ref={ ref } className={ `language-${ props.language }` }>
{ props.value }
</code>
</pre>
)
}
修改github-gist.css
文件
为了让显示效果更贴合Github的代码高亮显示,这里需要对highlight.js/styles/github-gist.css
稍作修改,修改如下:
.hljs {
display: block;
/*background: white;*/
/* 更改代码背景色 */
background: #f6f8fa;
/* 更改文字大小 */
font-size: 90%;
/* 设置行高 */
line-height: 1.45;
padding: 0.5em;
color: #333333;
overflow-x: auto;
}
Markdown组件
import React from 'react'
import ReactMarkdown from 'react-markdown/with-html'
import CodeBlock from './CodeBlock'
import styled from 'styled-components'
const Wrapper = styled.div`
max-width: 1012px;
margin: 12px auto;
padding-right: 16px;
padding-left: 16px;
box-sizing: border-box;
border-radius: 3px;
border: 1px solid #eee;
`
interface IProps {
content: string
}
function Markdown(props: IProps) {
return (
<Wrapper>
<ReactMarkdown source={props.content} renderers={{code: CodeBlock}}/>
</Wrapper>
)
}
export default Markdown
App.tsx
import React from 'react';
import './App.css';
import Markdown from './components/article/Markdown'
const content = `
# React-Notes
## React 核心概念
### JSX
#### JSX是什么?
- Fackbook起草的JS扩展语法
- 本质是一个JS对象,会被babel编译,最终会被转换为\`React.createElement\`
- 每个JSX表达式,有且仅有一个根节点
- React.Fragment(空节点相当于\`<></>\`)
- 每个JSX元素必须结束(XML规范)
\`\`\`jsx
<div className="App">
<h1>hello</h1>
<img />
</div>
\`\`\`
#### 在JSX中嵌入表达式
- 将表达式作为内容的一部分
- false,null和undefined不会显示
- 普通对象不可作为子元素
- 可以放置React元素对象
- 将表达式作为元素属性
- 属性使用小驼峰命名法
- 防止注入攻击
- 自动编码
- \`dangerouslySetInnerHTML\`
使用:
\`\`\`jsx
function Me() {
const person = { name: 'Flinn', friends: ['Leon', 'Monica'] }
return (
<div className="App">
<h1>hello</h1>
name: {person.name}
<br />
friends:
<ul>{ person.friends.map(friend => <li>{friend}</li>) }</ul>
</div>
)
}
\`\`\`
通常情况下,为防止注入攻击,React使用innerText进行页面的渲染,如有特殊需求,可使用\`dangerouslySetInnerHTML\`改为innerHTML:
\`\`\`jsx
function App() {
const content = '<h1>dangerous!!!</h1>'
return (
<div className="App" dangerouslySetInnerHTML={{__html: content}}>
</div>
)
}
\`\`\`
`
function App() {
return (
<div className="App">
<Markdown content={content}/>
</div>
);
}
export default App;
预览结果
