【前端】react-markdown配置解析

2023-11-18


react-markdown是一款github上开源的适用于react的markdown组件,可以基本实现markdown的功能,且可以根据自己的实际应用定制remark组件。官方给出该组件的好处是:

The two main reasons are that they often rely on dangerouslySetInnerHTML or have bugs with how they handle markdown. react-markdown uses a syntax tree to build the virtual dom which allows for updating only the changing DOM instead of completely overwriting. react-markdown is 100% CommonMark (optionally GFM) compliant and has extensions to support custom syntax.

本文将介绍react-markdown的配置,以及部分实用组件的配置和介绍,包括Katex、syntax-highlighter、Gfm以及TOC。react-markdown的源码和完全介绍请移步https://github.com/remarkjs/react-markdown

react-markdown基本配置

  1. 使用npm install react-markdown引入react-markdown包,注意该组件的旧版本和新版本使用配置差别较大,我目前为v7.1.0

  2. 一个简单的hello world:

    import React from 'react'
    import ReactMarkdown from 'react-markdown'
    import ReactDom from 'react-dom'
    
    ReactDom.render(<ReactMarkdown># Hello, *world*!</ReactMarkdown>, document.body)
    

    如此以来,简单的react-markdown就配置好啦!但是这种配置支持的语法较少,如表格、代码高亮、数学公式等均不支持,且无法实现同步预览效果。

同步预览配置

我使用的是redux来控制状态,当然也可以使用dva或者其他方式。

MdEditorComponent.js

import React, { Component } from 'react'
import styles from './MdEditorComponent.module.css'
import { connect } from 'react-redux'
import { editMarkdown } from '../../../redux/sync-actions'
import ReactMarkdownComponent from '../article-component/ReactMarkdownComponent'

const DEFAULT_SIZE = 500 //默认代码块高度

class MdEditorComponent extends Component {
  constructor (props) {
    super(props)
    this.state = {
      textareaHeight: DEFAULT_SIZE
    }
  }

  componentDidMount () {
    window.addEventListener('resize', this.handleResize) //监听resize
  }

  handleResize = e => {

  }

  //修改内容状态
  handleInputMarkdown = e => {
    let previewHeight = this.preview.scrollHeight
    let textareaHeight = e.target.scrollHeight
    let height = Math.max(previewHeight, textareaHeight, DEFAULT_SIZE)
    this.setState({ textareaHeight: height })
    this.props.editMarkdown(e.target.value)
  }

  //当鼠标选中textarea时
  handleKeyPressMarkdown = e => {
    let previewHeight = this.preview.scrollHeight
    let textareaHeight = e.target.scrollHeight
    let height = Math.max(previewHeight, textareaHeight, DEFAULT_SIZE)
    //下面是自定义的特殊按键触发的效果
    if (e.keyCode === 9) {
      e.preventDefault()
      this.props.editMarkdown(this.props.markdown + '\t')
    } else if (e.keyCode === 13)
      return false
    else if (e.keyCode === 17) { //left ctrl
      this.setState({ textareaHeight: height })
    } else if (e.keyCode === 8) { //backspace
      this.setState({ textareaHeight: height })
    } else if (e.keyCode === 192) { // ~
      // e.preventDefault()
    }
  }

  render () {
    return (
      <div className={styles.container} style={{
        height: this.state.textareaHeight //设置默认高度
      }}>
        <div className={styles.input}>
          <textarea style={{ border: '0px' }} spellCheck={false} value={this.props.markdown}
                    onKeyDown={this.handleKeyPressMarkdown}
                    onChange={this.handleInputMarkdown}/>
        </div>
        <div ref={div => this.preview = div} className={styles.md}>
          <ReactMarkdownComponent content={this.props.markdown}/>
        </div>
      </div>
    )
  }
}

//使用redux来控制状态
MdEditorComponent = connect(
  ({ $BlogState: { mdContent } }) => ({ markdown: mdContent }),
  { editMarkdown }
)(MdEditorComponent)

export default MdEditorComponent

reducer.js

export function $BlogState (state = initBlogState, { data, type }) {
  switch (type) {
    case EDIT_MARKDOWN:
      return { ...state, mdContent: data }
    default:
      return state
  }
}

initBlogState.js

初始的显示内容

export const initBlogState = {
  mdContent: `# Markdown Online Editor
## Subtitle

common content

### Little title

    Code Block
  
### Code Syntax Highlight
~~~js
console.log('hello randyzhang')
~~~
`,
}

action-types.js

export const EDIT_MARKDOWN = 'edit_markdown'

sync-actions.js

export const editMarkdown = data => actionFactory(EDIT_MARKDOWN, data)

store.js

import { applyMiddleware, combineReducers, createStore } from 'redux'
import { composeWithDevTools } from 'redux-devtools-extension'
import thunk from 'redux-thunk'
import { $BlogState } from './reducers'

const store = createStore(
  combineReducers({
    $BlogState,
  }),
  composeWithDevTools(applyMiddleware(thunk))
)

export default store

remark-Gfm配置

配置好后即可使用表格、删除线、任务列表、引用等操作。需要使用npm install remark-Gfm引入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
)

展示的效果为:

A paragraph with emphasis and strong importance.

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

  • Lists
  • todo
  • done

A table:

a b

syntax-highligh配置

使用该组件可以实现代码块的彩色,需要使用npm install react-syntax-hightlighter --save来引入react-syntax-highlighter包。

这里components中间的部分主要是针对输入的代码块语言匹配相应的代码高亮,如果非匹配成功则直接使用code形式展示。

import React from 'react'
import ReactDom from 'react-dom'
import ReactMarkdown from 'react-markdown'
import {Prism as SyntaxHighlighter} from 'react-syntax-highlighter'
import {dark} from 'react-syntax-highlighter/dist/esm/styles/prism'

const markdown = `Here is some JavaScript code:

~~~js
console.log('It works!')
~~~
`

ReactDom.render(
  <ReactMarkdown
    children={markdown}
    components={{
      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>
        )
      }
    }}
  />,
  document.body
)

rehype-katex和remark-math的配置

使用该组件可以轻松的翻译输入的数学公式,输入npm install remark-math rehype-katex引入相应的包。

注意:需要使用katex.css来展示相应的效果,否则会出现BUG

需要在index.html中添加上下列的话并下载包:

<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'

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

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

展示的效果为:

L = 1 2 ρ v 2 S C L L = \frac{1}{2} \rho v^2 S C_L L=21ρv2SCL

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的配置

如果你trusted environment (you trust the markdown),可以使用该配置使markdown支持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
)

个性化组件配置

有时候我们需要修改一些颜色、大小等,则可以按照一下规则进行修改:

<ReactMarkdown
  components={{
    // Map `h1` (`# heading`) to use `h2`s.
    h1: 'h2',
    // Rewrite `em`s (`*like so*`) to `i` with a red foreground color.
    em: ({node, ...props}) => <i style={{color: 'red'}} {...props} />
  }}
/>

总结

react-markdown作为一款适用于react的markdown组件,使用非常方便,且丰富的remark和rehype可以扩展很多功能,自己也可以定义remark组件,推荐大家来使用。

如果有好的使用方法或者更适合的组件也可以告诉我,互相学习和进步~

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【前端】react-markdown配置解析 的相关文章

随机推荐

  • 手把手教你Modelsim仿真【2020.4版本】

    首先新建一个文件夹 test5 打开Modelsim 依次选择 File gt Change Directory 把目录选择到创建的 test5 文件夹 创建库 依次选择 File gt New gt Library 一般我们选择第三个 库
  • 软文营销如何吸引用户情感意识引起共鸣

    当今互联网营销铺天盖地 自网络开始普及后 网络营销发展速度非常快 然而 我们需要在众多营销中取胜就需要技术创新 不管平台如何变化 有一个要素仍然至关重要 写好广告文案 因为文案内容才是读者了解你的关键所在 今天178软文网小编将分享我们最好
  • 大模型开发:从数据挖掘到智能应用

    在当今的数字化时代 数据的生成和处理已经成为一项重要的战略任务 随着大数据技术的发展 企业 组织以及个人对海量数据的需求越来越大 这也就催生了数据挖掘算法模型开发的快速发展 数据挖掘算法模型开发是一种从大量数据中提取有价值信息的过程 这些信
  • 国服ps4如何修改服务器地址,国服ps4如何修改服务器地址

    国服ps4如何修改服务器地址 内容精选 换一换 本节介绍如何查看云服务器的mac地址 云服务器的mac地址不支持修改 登录Linux云服务器 执行以下命令 查看云服务器的mac地址 ifconfig查看MAC地址ifconfig登录Linu
  • 【3分钟速读】运营到底是干啥的?

    欢迎关注天善智能 我们是专注于商业智能BI 人工智能AI 大数据分析与挖掘领域的垂直社区 学习 问答 求职一站式搞定 作者 陈老师 在咨询行业打拼了10 年 在如何诊断经营问题 建立分析体系 解决专项问题上有超过30个大型项目积累与实战 天
  • 时间序列预测(一)基于Prophet的销售额预测

    时间序列预测 一 基于Prophet的销售额预测 小O 小H 有没有什么方法能快速的预测下未来的销售额啊 小H Facebook曾经开源了一款时间序列预测算法fbprophet 简单又快速 传统的时间序列算法很多 例如AR MA ARIMA
  • 创建对象的几种方式

    一 工厂模式 工厂模式解决了创建相似对象的问题 但却没有解决对象识别的问题 怎样知道一个对象的类型 function createPerson name age job var o new Object o name name o age
  • 走进大数据,感受大数据

    摘要 大数据时代已经到来 现阶段 我国大数据产业发展如何 大数据应用领域在哪 大数据价值在哪里 带着这些疑问 走进大数据 感受大数据带来的神奇魔力 关注作者 需要大数据学习视频资料 其他文章可以找到大师组织 2017年9月8日 腾讯董事会主
  • shapley和树的shap

    提示 文章写完后 目录可以自动生成 如何生成可参考右边的帮助文档 shapley and shap Shapley交互阶的计算 关于树结构Shap的计算 Shapley交互阶的计算 首先一阶的计算公式 二阶 交互值 计算 三阶计算 一般式
  • Qt-窗口消息处理机制及拦截消息的五种方法

    Qt 拦截消息的五种方法 覆写框架类QCoreApplication的notify函数 这个函数将得到整个框架中所有窗口的消息 给框架类安装一个消息过滤器 QCoreApplication gt nativeEventFilter filt
  • java中创建类的数组

    例题 定义一个People类 要求如下 1 成员变量 name height weight 分别表示姓名 身高 cm 和体重 kg 2 构造方法通过参数实现对成员变量的赋初值操作 3 成员方法int check 该方法返回0 1 1 分别表
  • qt 串口粘包_Qt开发串口

    首先 在工程文件里面 QT serialport 在头文件里面 include 1 配置打开串口 QSerialPort myserial new QSerialPort this gt myserial gt setPortName CO
  • Linux slab 分配器剖析

    http www ibm com developerworks cn linux l linux slab allocator 了解 Linux 内存管理的方式 良好的操作系统性能部分依赖于操作系统有效管理资源的能力 在过去 堆内存管理器是
  • 【C++】指针和引用的区别

    引用的主要用途 修饰函数的形参和返回值 指针和引用的区别 引用没有空引用的概念 指针有 没有引用的引用 指针有二级指针 三级指针 引用必须初始化 指针不一定 但是最好初始化 防止野指针 引用加一 是引用实体加一 而指针是向后偏移一个类型的大
  • Ubuntu14.04下配置OpenGL及测试代码

    ubuntu14 04 64位下 默认是没有安装OpenGL相关依赖库的 若安装 则依次执行如下几条命令即可 sudo apt get update sudo apt get install build essential sudo apt
  • 【小5聊】jQuery基础之获取指定时间月份的最后一天

    描述 由于每个月份的天数不一样 所以每一个月份的最后一天值就不一样 new Date new Date 2020 06 01 00 05 00 setMonth new Date 2020 06 01 00 05 00 getMonth 0
  • 基于Java+Spring boot+Mybatis Plus 实现H5在线点餐系统

    前言 商城系统就是功能完善的网上销售系统 主要包括产品发布 在线订购 在线支付 在线客服 订单管理等功能模块 商城系统的日常管理如 商品添加修改 订单管理 回复客户留言等都是在线操作的 操作简单 会上网者就可以操作 商城系统成本低 节省开发
  • verilog中wire和reg类型的区别

    module counter parameter CNT MAX 25 d24 999 999 input wire sys clk input wire sys rst n output reg led out reg 24 0 cnt
  • state和props的区别__react

    首先说明 state和props是每个组件都有的 其次 state可变 但props不可变 这是官网给出的说法 但实操过程中 state的确可变 但props也可以变 是不是fb搞错了 当然不是 这里的可变与不可变 说的是改变后 是否会重新
  • 【前端】react-markdown配置解析

    文章目录 react markdown基本配置 同步预览配置 MdEditorComponent js reducer js initBlogState js action types js sync actions js store js