react版本markdown编辑器md-editor-rt,支持ssr

md-editor-rt是前段时间学习vue3时开发的一个vue3版本编辑器md-editor-v3的同系列项目,它是react版本的,因为vue3版本的也是使用tsx完成的,所以react版本的代码相差不大。

作者的博客前端内容是使用nextjs开发的,而内容管理又是使用vue开发的,提取编辑文章和内容渲染的功能形成了这个项目。

1. 预览

1.1 功能预览

  1. 快捷插入内容工具栏、编辑器浏览器全屏、页面内全屏等;
  2. 内置的白色主题和暗黑主题,支持绑定切换;
  3. 支持快捷键插入内容;
  4. 支持使用 prettier 格式化内容(使用 CDN 方式引入,只支持格式化 md 内容,可在代码内设置关闭);
  5. 支持多语言,支持自行扩展语言;
  6. 支持复制粘贴上传图片,图片裁剪上传;
  7. 支持渲染模式(不显示编辑器,只显示 md 预览内容,无额外监听);
  8. 支持ssr,支持在nextjs中使用;

1.2 在线预览

文档与在线预览:传送门

1.3 图片预览

默认模式

image.png

暗黑模式

image.png

2. 基本使用

react版本目前没有导出umd版本。

2.1 常规单页应用

import React, { useState } from 'react';
import Editor from 'md-editor-rt';
import './index.less';

export default () => {
  const [md, setMd] = useState('');
  return <Editor theme="dark" modelValue={md} onChange={(v) => setMd(v)} />;
};

2.2 服务端渲染

服务端渲染的情况一般是提供markdown文本渲染内容而非加载整个编辑器,下面的例子即是使用仅预览模式的情况。

import React, { useState } from 'react';
import Editor from 'md-editor-rt';
import './index.less';

export default () => {
  const [md] = useState('# title');
  
  // 仅预览模式只需提供md文本而不会改变文本
  return <Editor editorId="article-content" theme="dark" modelValue={md} previewOnly />;
};

从写法来讲,没有区别,值得注意的是,服务端渲染时最好提供editorId属性,由于默认情况下编辑器会随机生成editorId,所以会造成服务端的html内容和客户端渲染的html内容不一致而提示错误(该问题在nextjs基础环境中可以重现)。

2.3 标题导航实现

react版本最初就提供了onGetCatalog属性,在编辑器每一次render后会调用该方法,将markdown内容中的标题作为列表传递回来,结构如下:

interface HeadList {
  text: string;
  level: 1 | 2 | 3 | 4 | 5 | 6;
}

// eg
const [heads, setHeads] = useState<HeadList>([{ text: '预览', level: '2' }]);

在作者的博客开源blog-template-nextjs中,已经基于antd封装了导航菜单,使用相当简单:

import Topicfy from '@/Topicfy';

// 将`onGetCatalog`取得的标题列表直接赋值到`Topicfy`组件即可
<Topicfy heads={heads} />

3. 编辑器的功能演示

3.1 扩展库链接

编辑器扩展内容大多使用了cdn,考虑了无外网情况,支持了内网链接扩展,演示(假设外部库都在根目录下):

import React, { useState } from 'react';
import MdEditor from 'md-editor-rt';
import 'md-editor-rt/lib/style.css';

export default () => {
  const [text] = useState('');

  return (
    <MdEditor
      modelValue={text}
      highlightJs="/highlight.min.js"
      highlightCss="/atom-one-dark.min.css"
      prettierCDN="/standalone.js"
      prettierMDCDN="/parser-markdown.js"
      cropperJs="/cropper.min.js"
      cropperCss="/cropper.min.css"
      iconfontJs="/iconfont.js"
    />
  );
};

3.2 工具栏自定义

默认的全部工具栏,并且每个功能都绑定了快捷键,如果需要选择性显示工具栏,提供了两个api:toolbarstoolbarsExclude,前者显示数组中的全部,后者屏蔽数组中的全部,后者的权重更大。下面是个参考:

案例不显示github按钮

import React, { useState } from 'react';
import MdEditor from 'md-editor-rt';
import 'md-editor-rt/lib/style.css';

export default () => {
  const [data] = useState({
    text: '',
    toobars: [
      'bold',
      'underline',
      'italic',
      'strikeThrough',
      'sub',
      'sup',
      'quote',
      'unorderedList',
      'orderedList',
      'codeRow',
      'code',
      'link',
      'image',
      'table',
      'revoke',
      'next',
      'save',
      'pageFullscreen',
      'fullscreen',
      'preview',
      'htmlPreview'
    ],
    toolbarsExclude: ['github']
  });

  return (
    <>
      <MdEditor modelValue={data.text} toolbars={data.toobars} />
      <MdEditor modelValue={data.text} toolbarsExclude={data.toolbarsExclude} />
    </>
  );
};

3.3 扩展语言

编辑器默认内置了中文和英文,并且两者都可以通过扩展api覆盖,该功能主要用来设置内容提示,比如弹窗中的标题等。

扩展一门语言,我们取名为zh-NB

import React, { useState } from 'react';
import MdEditor, { StaticTextDefaultValue } from 'md-editor-rt';
import 'md-editor-rt/lib/style.css';

const languageUserDefined: { 'zh-NB': StaticTextDefaultValue } = {
  'zh-NB': {
    toolbarTips: {
      bold: '加粗',
      underline: '下划线',
      italic: '斜体',
      strikeThrough: '删除线',
      title: '标题',
      sub: '下标',
      sup: '上标',
      quote: '引用',
      unorderedList: '无序列表',
      orderedList: '有序列表',
      codeRow: '行内代码',
      code: '块级代码',
      link: '链接',
      image: '图片',
      table: '表格',
      revoke: '后退',
      next: '前进',
      save: '保存',
      prettier: '美化',
      pageFullscreen: '浏览器全屏',
      fullscreen: '屏幕全屏',
      preview: '预览',
      htmlPreview: 'html代码预览',
      github: '源码地址'
    },
    titleItem: {
      h1: '一级标题',
      h2: '二级标题',
      h3: '三级标题',
      h4: '四级标题',
      h5: '五级标题',
      h6: '六级标题'
    },
    linkModalTips: {
      title: '添加',
      descLable: '链接描述:',
      descLablePlaceHolder: '请输入描述...',
      urlLable: '链接地址:',
      UrlLablePlaceHolder: '请输入链接...',
      buttonOK: '确定',
      buttonUpload: '上传'
    },
    clipModalTips: {
      title: '裁剪图片上传',
      buttonUpload: '上传'
    },
    copyCode: {
      text: '复制代码',
      tips: '已复制'
    }
  }
};

export default () => {
  const [data] = useState({
    text: '',
    language: 'zh-NB',
    languageUserDefined
  });

  return (
    <MdEditor
      modelValue={data.text}
      language={data.language}
      languageUserDefined={data.languageUserDefined}
    />
  );
};

如果key = 'zh-CN',就可以实现中文覆盖,以此类推。

3.4 主题切换

这一块相对比较简单了,内置了暗黑主题默认主题,通过themeapi切换,demo如下:

import React, { useState } from 'react';
import MdEditor from 'md-editor-rt';
import 'md-editor-rt/lib/style.css';

export default () => {
  const [data] = useState({
    text: '',
    theme: 'dark'
  });
  return <MdEditor modelValue={data.text} theme={data.theme} />;
};

结尾

更多的更新请关注:md-editor-rt

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,132评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,802评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,566评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,858评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,867评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,695评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,064评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,705评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,915评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,677评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,796评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,432评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,041评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,992评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,223评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,185评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,535评论 2 343

推荐阅读更多精彩内容