求类似Megadraft/TipTap的无工具栏React文本编辑器
定制符合需求的React文本编辑器(基于TipTap)
TipTap本身具备极强的可扩展性,完全可以定制出你需要的无工具栏、左侧带加号插入面板、支持选中文本修改样式的编辑器,以下是具体实现方案:
1. 基础依赖安装
首先安装TipTap核心包及所需扩展:
npm install @tiptap/react @tiptap/extension-image @tiptap/extension-video @tiptap/extension-table @tiptap/extension-list-item @tiptap/extension-ordered-list @tiptap/extension-bullet-list @tiptap/extension-document @tiptap/extension-text
2. 核心实现代码
import React, { useState } from 'react'; import { EditorProvider, useEditor, EditorContent } from '@tiptap/react'; import Document from '@tiptap/extension-document'; import Text from '@tiptap/extension-text'; import Image from '@tiptap/extension-image'; import Video from '@tiptap/extension-video'; import Table from '@tiptap/extension-table'; import TableRow from '@tiptap/extension-table-row'; import TableCell from '@tiptap/extension-table-cell'; import BulletList from '@tiptap/extension-bullet-list'; import OrderedList from '@tiptap/extension-ordered-list'; import ListItem from '@tiptap/extension-list-item'; const EditorComponent = () => { const [showInsertMenu, setShowInsertMenu] = useState(false); const editor = useEditor({ extensions: [ Document, Text, Image.configure({ inline: false }), Video.configure({ inline: false }), Table.configure({ resizable: true }), TableRow, TableCell, BulletList, OrderedList, ListItem, ], content: '<p>开始编辑...</p>', }); // 插入内容逻辑 const insertContent = (type) => { if (!editor) return; switch(type) { case 'image': const imageUrl = prompt('输入图片URL:'); imageUrl && editor.chain().focus().insertContent(`<img src="${imageUrl}" />`).run(); break; case 'video': const videoUrl = prompt('输入视频URL:'); videoUrl && editor.chain().focus().insertContent(`<video src="${videoUrl}" controls></video>`).run(); break; case 'table': editor.chain().focus().insertTable({ rows: 3, cols: 3 }).run(); break; default: break; } setShowInsertMenu(false); }; // 切换列表样式 const toggleList = (type) => { if (!editor) return; type === 'bullet' ? editor.chain().focus().toggleBulletList().run() : editor.chain().focus().toggleOrderedList().run(); }; return ( <div style={{ display: 'flex', position: 'relative', width: '100%', height: '600px', border: '1px solid #eee' }}> {/* 左侧加号按钮及插入菜单 */} <div style={{ position: 'absolute', left: '10px', top: '10px', zIndex: 10 }}> <button onClick={() => setShowInsertMenu(!showInsertMenu)} style={{ width: '40px', height: '40px', borderRadius: '50%', border: 'none', backgroundColor: '#007bff', color: 'white', fontSize: '24px', cursor: 'pointer' }} > + </button> {showInsertMenu && ( <div style={{ marginTop: '8px', backgroundColor: 'white', border: '1px solid #ddd', borderRadius: '4px', padding: '8px', boxShadow: '0 2px 8px rgba(0,0,0,0.1)' }}> <button onClick={() => insertContent('image')} style={{ display: 'block', width: '100%', padding: '8px', border: 'none', backgroundColor: 'transparent', cursor: 'pointer', textAlign: 'left' }}>插入图片</button> <button onClick={() => insertContent('video')} style={{ display: 'block', width: '100%', padding: '8px', border: 'none', backgroundColor: 'transparent', cursor: 'pointer', textAlign: 'left' }}>插入视频</button> <button onClick={() => insertContent('table')} style={{ display: 'block', width: '100%', padding: '8px', border: 'none', backgroundColor: 'transparent', cursor: 'pointer', textAlign: 'left' }}>插入表格</button> </div> )} </div> {/* 编辑器内容区域 */} <EditorContent editor={editor} style={{ flex: 1, padding: '20px', paddingLeft: '60px' }} /> {/* 选中文本后的列表切换快捷按钮 */} {editor && editor.isActive('listItem') && ( <div style={{ position: 'absolute', right: '10px', top: '10px', zIndex: 10 }}> <button onClick={() => toggleList('bullet')} style={{ marginRight: '8px', padding: '6px 12px', border: '1px solid #ddd', borderRadius: '4px', cursor: 'pointer' }}>项目符号</button> <button onClick={() => toggleList('ordered')} style={{ padding: '6px 12px', border: '1px solid #ddd', borderRadius: '4px', cursor: 'pointer' }}>编号列表</button> </div> )} </div> ); }; const App = () => { return ( <EditorProvider> <EditorComponent /> </EditorProvider> ); }; export default App;
3. 关键功能说明
- 左侧加号插入面板:点击加号弹出菜单,支持插入图片、视频、表格,可按需扩展更多内容类型(如代码块、引用块)。
- 选中文本样式修改:示例实现了列表样式切换,若需添加加粗、斜体等样式,只需引入对应TipTap扩展(如
Bold、Italic)并调用toggleBold()这类方法即可。 - 无工具栏设计:完全摒弃传统顶部工具栏,所有操作通过左侧插入按钮和选中文本后的快捷按钮完成。
4. 扩展优化建议
- 可结合React UI组件库(如Ant Design、Material UI)将插入菜单改为更美观的下拉面板。
- 选中文本的样式修改可改为右键上下文菜单,通过监听编辑器
selectionUpdate事件判断选中状态后触发。 - 图片/视频插入可替换为文件上传逻辑,对接后端接口实现本地文件上传。
内容的提问来源于stack exchange,提问作者op po
相关产品推荐
相关产品推荐

