React markdown 编辑器

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

安装

安装 markdown 预览插件 react-markdown

npm install react-markdown

或者:

yarn add react-markdown

安装 markdown 编辑器插件 for-editor

yarn add for-editor

或者:

npm install for-editor

安装代码高亮插件包 react-syntax-highlighter

npm install react-syntax-highlighter

或者:

yarn add react-syntax-highlighter

安装 remark-math

npm install remark-math

或者:

yarn add remark-math

安装 rehype-katex

npm install rehype-katex

或者:

yarn add rehype-katex

安装 rehype-raw

npm install rehype-raw

或者:

yarn add rehype-raw

组件依赖

组件涉及的依赖及版本 package.json

{
  "dependencies": {
    "antd": "^4.16.10",
    "less": "^4.1.1",
    "less-loader": "4.0.1",
    "react": "^17.0.2",
    "react-dom": "^17.0.2",
    "react-router-dom": "^5.2.0",
    "for-editor": "^0.3.5", // Markdown编辑
    "react-markdown": "^8.0.7", // Markdown预览
    "rehype-katex": "^6.0.2", // 数学公式katex语法
    "rehype-raw": "^6.1.1", // 支持HTML语法解析
    "remark-math": "^5.1.1", // 支持数学公式 
    "react-scripts": "4.0.3",
    "typescript": "^5.0.4",
  }
}
  • for-editormarkdown 编辑器
  • react-markdownmarkdown 内容预览及展示
  • rehype-raw:解析 HTML 文本富文本内容
  • remark-math、rehype-katex:数学公式支持及语法解析使用(数学公式的样式展示需要 katex.min.css 文件支持)

基本使用

编辑器 for-editor

属性

名称类型默认值描述
valueString-输入框内容
placeholderString开始编辑…占位文本
lineNumBooleantrue是否显示行号
styleObject-编辑器样式
heightString600px编辑器高度
previewBooleanfalse预览模式
expandBooleanfalse全屏模式
subfieldBooleanfalse双栏模式(预览模式激活下有效)
languageStringzh-CN语言(支持 zh-CN:中文简体, en:英文)
toolbarObject如下自定义工具栏
/*
  默认工具栏按钮全部开启, 传入自定义对象
  例如: {
    h1: true, // h1
    code: true, // 代码块
    preview: true, // 预览
  }
  此时, 仅仅显示此三个功能键
  注:传入空对象则不显示工具栏
 */

toolbar: {
  h1: true, // h1
  h2: true, // h2
  h3: true, // h3
  h4: true, // h4
  img: true, // 图片
  link: true, // 链接
  code: true, // 代码块
  preview: true, // 预览
  expand: true, // 全屏
  /* v0.0.9 */
  undo: true, // 撤销
  redo: true, // 重做
  save: true, // 保存
  /* v0.2.3 */
  subfield: true, // 单双栏模式
}

事件

名称参数类型默认值描述
onChangeString: valuefunction(e)-内容改变时回调
onSaveString: valuefunction(e)-保存时回调
addImgFile: filefunction(e)-添加图片时回调

快捷键

名称描述
tab两个空格缩进
ctrl+s保存
ctrl+z上一步
ctrl+y下一步

views/md-editor/ 文件夹下面新建 MdEditor.js 文件:

import React, { useState } from "react"
import MdEditor from 'for-editor'

const DemoEditor = () => {
  /** 默认工具栏按钮全部开启, 传入自定义对象
  例如: {
    h1: true, // h1
    code: true, // 代码块
    preview: true, // 预览
  }
  此时, 工具栏只显示此三个功能键(注:传入空对象则不显示工具栏)
  */
  // 工具栏菜单
  const toolbar = {
    h1: true, // h1
    h2: true, // h2
    h3: true, // h3
    h4: true, // h4
    img: true, // 图片
    link: true, // 链接
    code: true, // 代码块
    preview: true, // 预览
    expand: true, // 全屏
    /* v0.0.9 */
    undo: true, // 撤销
    redo: true, // 重做
    save: true, // 保存
    /* v0.2.3 */
    subfield: true, // 单双栏模式
  };

  // 保存Markdown文本内容
  const [mdContent, setMdContent] = useState('')

  // 上传图片
  function uploadImg (file) {
    console.log('file', file);
  };
  // 输入内容改变
  function handleEditorChange (value) {
    console.log('handleChange', value);
    setMdContent(value)
  }
  // 保存输入内容
  function handleEditorSave (value) {
    console.log('handleEditorSave', value);
  }
  return (
    <MdEditor placeholder="请输入Markdown文本" height={600} lineNum={false}
      toolbar={toolbar} value={mdContent} onChange={handleEditorChange} onSave={handleEditorSave} addImg={uploadImg} />
  )
}
export default DemoEditor

App.js 中引入 md-editor.js 文件:

import './assets/css/App.css';
import MdCtxEditor from './views/md-editor/MdEditor';

function App () {
  return (
    <div className="App">
      <MdCtxEditor />
    </div>
  );
}
export default App;

页面效果:
在这里插入图片描述

预览 react-markdown

views/md-editor/ 文件夹下面新建 MdPreview.js 文件:

import React, { useEffect, useState } from "react"
import ReactMarkdown from 'react-markdown'

const DemoPage = () => {
  const [docmentContent, setDocmentContent] = useState('')
  const content = '# This is title 1\n\n## This is title 2\n\n### This is title 3\n\nAnd this is a paragraph\n\n**A paragraph with strong importance**\n\n*A block quote with ~strikethrough~*'
  useEffect(() => {
    setDocmentContent(content)
  }, [])
  return (
    <div className="markdown-body" style={{ padding: '30px', borderRadius: '10px' }}>
      <ReactMarkdown children={docmentContent} />
    </div>
  )
}
export default DemoPage

App.js 中引入 MdPreview.js 文件:

import './assets/css/App.css';
import MdCtxPreview from './views/md-editor/MdPreview';

function App () {
  return (
    <div className="App">
      <MdCtxPreview />
    </div>
  );
}
export default App;

页面效果:
在这里插入图片描述

代码块高亮

修改 MdPreview.js 文件:

import React, { useEffect, useState } from "react"
import ReactMarkdown from 'react-markdown'

import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'
// 设置高亮样式
import { xonokai } from 'react-syntax-highlighter/dist/esm/styles/prism'

const Code = {
  code ({ node, inline, className, children, ...props }) {
    const match = /language-(\w+)/.exec(className || '')
    return !inline && match ? (
      <SyntaxHighlighter
        children={String(children).replace(/\n$/, '')}
        style={xonokai}
        language={match[1]}
        PreTag="div"
        {...props}
      />
    ) : (
      <code className={className} {...props}>
        {children}
      </code>
    )
  }
}
const DemoPage = () => {
  const [docmentContent, setDocmentContent] = useState('')
  const content = `This is some JavaScript code:
  ~~~js
  console.log('Hello world!')
  ~~~
  `
  useEffect(() => {
    setDocmentContent(content)
  }, [])
  return (
    <div className="markdown-body" style={{ padding: '30px', borderRadius: '10px' }}>
      <ReactMarkdown
        children={docmentContent}
        components={Code}
      />
    </div>
  )
}
export default DemoPage

页面效果:
在这里插入图片描述

支持 HTML

修改 MdPreview.js 文件:

import React, { useEffect, useState } from "react"
import ReactMarkdown from 'react-markdown'

import rehypeRaw from 'rehype-raw';

const DemoPage = () => {
  const [docmentContent, setDocmentContent] = useState('')
  
  const content = `<div class="note">Some *emphasis* and <strong>strong</strong>!</div>`
  
  useEffect(() => {
    setDocmentContent(content)
  }, [])
  return (
    <div className="markdown-body" style={{ padding: '30px', borderRadius: '10px' }}>
      <ReactMarkdown children={docmentContent}
        rehypePlugins={[rehypeRaw]} />
    </div>
  )
}
export default DemoPage

页面效果:
在这里插入图片描述

rehype-katexremark-math 展示数学公式

使用 rehype-katexremark-math 可以轻松的翻译输入的数学公式。

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

index.html 中引入公式解析样式文件:

<!-- 解析Markdown数学公式样式 -->
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.13.13/dist/katex.min.css" integrity="sha384-RZU/ijkSsFbcmivfdRBQDtwuwVqK7GMOw6IMvKyeWL2K5UAlyp6WonmB8m7Jd0Hn" crossorigin="anonymous">

修改 MdPreview.js 文件:

import React, { useEffect, useState } from "react"
import ReactMarkdown from 'react-markdown'

import remarkMath from 'remark-math'
import rehypeKatex from 'rehype-katex'

const DemoPage = () => {
  const [docmentContent, setDocmentContent] = useState('')
  const ctx = `$$
  I = \int_0^{2\pi} \sin(x)\,dx
  $$`
  useEffect(() => {
    setDocmentContent(ctx)
  }, [])
  return (
    <div className="markdown-body" style={{ padding: '30px', borderRadius: '10px' }}>
      <ReactMarkdown
        children={docmentContent}
        remarkPlugins={[remarkMath]}
        rehypePlugins={[rehypeKatex]}
      />
    </div>
  )
}
export default DemoPage

页面效果:
在这里插入图片描述

相关链接

react-markdown github 源码
for-editor github
markdown-navbar github

  • 4
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值