MarkdownEditor 是一个基于 Milkdown/Crepe 构建的现代化 React Markdown 编辑器组件,提供了丰富的编辑功能和完整的 API 接口。
- 🔥 所见即所得 (WYSIWYG) - 实时预览 Markdown 渲染效果,无需左右分栏
- 🎨 语法高亮 - 支持多种编程语言的代码高亮
- ⚡ 斜杠命令 - 输入
/快速插入各种 Markdown 元素 - 📊 图表支持 - 内置 Mermaid 图表支持
- ✅ 任务列表 - 支持勾选框和任务管理
- 🎛️ 完整 API - 提供设置、获取、清空等所有常用方法
- 🔧 高度可定制 - 支持功能开关和样式自定义
- 📱 响应式设计 - 适配各种屏幕尺寸
- ⚙️ TypeScript - 完整的类型定义支持
- 基础语法: 标题、段落、粗体、斜体、删除线、行内代码
- 列表: 有序列表、无序列表、任务列表
- 引用: 嵌套引用块
- 代码: 代码块和行内代码,支持语法高亮
- 链接: 普通链接和图片链接
- 表格: 支持对齐的表格
- 分割线: 水平分割线
- 图表: Mermaid 流程图、时序图等
- Node.js >= 16.0.0
- React >= 18.0.0
- TypeScript >= 5.0.0
npm install
# 或
yarn install
# 或
pnpm installnpm run dev
# 或
yarn dev
# 或
pnpm dev访问 http://localhost:5173 查看编辑器演示。
npm run build
# 或
yarn build
# 或
pnpm buildnpm install @milkdown/crepe @milkdown/react
# 或
yarn add @milkdown/crepe @milkdown/react# 复制核心组件文件到你的项目
cp -r src/components/MarkdownEditor* your-project/src/components/
cp -r src/components/SlashMenu* your-project/src/components/
cp -r src/components/MarkdownInputDialog* your-project/src/components/import React, { useRef } from 'react';
import { MarkdownEditor, MarkdownEditorRef } from './components/MarkdownEditor';
const App = () => {
const editorRef = useRef<MarkdownEditorRef>(null);
const handleGetContent = () => {
const content = editorRef.current?.getMarkdown();
console.log(content);
};
return (
<div>
<button onClick={handleGetContent}>获取内容</button>
<MarkdownEditor
ref={editorRef}
initialContent="# Hello World"
height="500px"
onChange={(markdown) => console.log('内容变化:', markdown)}
/>
</div>
);
};const FormExample = () => {
const editorRef = useRef<MarkdownEditorRef>(null);
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
const content = editorRef.current?.getMarkdown();
// 提交表单
console.log('提交内容:', content);
};
return (
<form onSubmit={handleSubmit}>
<MarkdownEditor
ref={editorRef}
initialContent="请输入内容..."
height="300px"
/>
<button type="submit">提交</button>
</form>
);
};const ControlExample = () => {
const editorRef = useRef<MarkdownEditorRef>(null);
const actions = [
{
label: '插入标题',
action: () => editorRef.current?.insertText('\n# 新标题\n'),
},
{
label: '插入代码块',
action: () => editorRef.current?.insertText('\n```javascript\n// 你的代码\n```\n'),
},
{
label: '清空内容',
action: () => editorRef.current?.clear(),
},
{
label: '切换只读',
action: () => {
const isReadonly = editorRef.current?.getReadonly();
editorRef.current?.setReadonly(!isReadonly);
},
},
];
return (
<div>
<div style={{ marginBottom: '16px' }}>
{actions.map(({ label, action }) => (
<button key={label} onClick={action} style={{ marginRight: '8px' }}>
{label}
</button>
))}
</div>
<MarkdownEditor ref={editorRef} height="400px" />
</div>
);
};| 属性 | 类型 | 默认值 | 描述 |
|---|---|---|---|
initialContent |
string |
'' |
初始内容 |
readonly |
boolean |
false |
是否为只读模式 |
placeholder |
string |
'输入 / 唤起命令...' |
占位符文本 |
height |
string | number |
'auto' |
编辑器高度 |
width |
string | number |
'100%' |
编辑器宽度 |
className |
string |
'' |
自定义样式类名 |
style |
CSSProperties |
{} |
自定义样式 |
showLoading |
boolean |
true |
是否显示加载状态 |
| 属性 | 类型 | 默认值 | 描述 |
|---|---|---|---|
codeHighlight |
boolean |
true |
是否启用代码高亮 |
diagram |
boolean |
true |
是否启用图表支持 |
slashMenu |
boolean |
true |
是否启用斜杠菜单 |
| 事件 | 类型 | 描述 |
|---|---|---|
onChange |
(markdown: string) => void |
内容变化时触发 |
onReady |
(editor: MarkdownEditorRef) => void |
编辑器就绪时触发 |
onFocus |
() => void |
获得焦点时触发 |
onBlur |
() => void |
失去焦点时触发 |
// 获取 Markdown 内容
const content = editorRef.current?.getMarkdown();
// 设置 Markdown 内容
editorRef.current?.setMarkdown('# 新标题');
// 清空编辑器
editorRef.current?.clear();// 在光标位置插入文本
editorRef.current?.insertText('**加粗文本**');
// 获取选中的文本
const selected = editorRef.current?.getSelectedText();// 设置只读模式
editorRef.current?.setReadonly(true);
// 获取只读状态
const isReadonly = editorRef.current?.getReadonly();
// 聚焦编辑器
editorRef.current?.focus();
// 失去焦点
editorRef.current?.blur();// 获取底层 Crepe 实例
const crepe = editorRef.current?.getCrepeInstance();
// 销毁编辑器
editorRef.current?.destroy();.markdown-editor {
--primary-color: #3370ff;
--bg-color: #ffffff;
--text-color: #1f2329;
--border-color: #dee0e3;
}<MarkdownEditor
className="my-custom-editor"
style={{
border: '2px solid #e1e5e9',
borderRadius: '12px',
boxShadow: '0 4px 12px rgba(0, 0, 0, 0.1)',
}}
height="500px"
/>.markdown-editor.dark {
--bg-color: #1f2329;
--text-color: #ffffff;
--border-color: #3c4043;
}src/
├── components/
│ ├── MarkdownEditor.tsx # 主编辑器组件
│ ├── MarkdownEditorExample.tsx # 使用示例
│ ├── MarkdownEditor.md # 详细文档
│ ├── SlashMenu.tsx # 斜杠菜单组件
│ ├── MarkdownInputDialog.tsx # 内容输入对话框
│ ├── DiagramView.tsx # 图表视图组件
│ ├── Editor.tsx # 原始编辑器组件
│ └── index.ts # 导出文件
├── App.tsx # 应用入口
├── main.tsx # 主文件
└── index.css # 全局样式
- React 18 - UI 框架
- TypeScript 5 - 类型安全
- Vite - 构建工具
- Milkdown v7 - Markdown 编辑器核心
- ProseMirror - 底层富文本编辑器
- Prism - 代码语法高亮
- Mermaid - 图表支持
-
数学公式支持:
npm install @milkdown/plugin-math
-
协作功能:
npm install yjs @milkdown/plugin-collab
-
文件上传:
npm install @milkdown/plugin-upload
const customPlugin = new Plugin({
key: new PluginKey('custom-plugin'),
props: {
handleKeyDown(view, event) {
// 自定义键盘快捷键
return false;
},
},
});-
克隆项目
git clone <repository-url> cd markdown-editor-wysiwyg
-
安装依赖
npm install
-
启动开发服务器
npm run dev
# 类型检查
npm run type-check
# 代码检查
npm run lint
# 修复代码格式
npm run lint:fix
# 格式化代码
npm run format# 构建生产版本
npm run build
# 预览构建结果
npm run preview- 懒加载: 按需加载插件和组件
- 防抖处理: 对
onChange事件进行防抖处理 - 内存管理: 组件卸载时自动清理编辑器实例
- 虚拟滚动: 大文档时启用虚拟滚动(可选)
A: 使用 initialContent 属性或 setMarkdown() 方法。
<MarkdownEditor initialContent="# 初始内容" />A: 使用 onChange 回调或定时调用 getMarkdown()。
<MarkdownEditor onChange={(markdown) => console.log(markdown)} />A: 通过 ProseMirror 插件添加自定义快捷键。
A: 支持现代浏览器 (Chrome 70+, Firefox 65+, Safari 12+, Edge 79+)
- ✨ 发布初始版本
- 🔥 完整的 Markdown 编辑功能
- 🎛️ 丰富的 API 接口
- 📱 响应式设计
- ⚙️ TypeScript 支持
欢迎提交 Issue 和 Pull Request!
- Fork 项目
- 创建特性分支 (
git checkout -b feature/AmazingFeature) - 提交更改 (
git commit -m 'Add some AmazingFeature') - 推送到分支 (
git push origin feature/AmazingFeature) - 开启 Pull Request
本项目采用 MIT 许可证 - 查看 LICENSE 文件了解详情。
- Milkdown - 强大的 Markdown 编辑器框架
- ProseMirror - 底层的富文本编辑器
- Mermaid - 图表和流程图支持
- Vite - 现代化的构建工具
如果你在使用过程中遇到问题,可以:
- 📧 提交 GitHub Issue
- 📖 查看 详细文档
- 🎮 尝试 在线演示
如果这个项目对你有帮助,请给个 ⭐️ 支持一下!
Made with ❤️ by Your Name