如何在React集成的Tiptap编辑器中基于Image扩展实现图片异步上传?
React + Tiptap 实现异步图片上传功能
一、自定义带上传逻辑的Image扩展
基于Tiptap官方Image扩展扩展,添加上传状态管理与URL替换逻辑:
import { Image } from '@tiptap/extension-image'; export const UploadImage = Image.extend({ addAttributes() { return { ...this.parent?.(), // 新增属性标记是否正在上传 uploading: { default: false, parseHTML: element => element.hasAttribute('data-uploading'), renderHTML: attributes => { if (attributes.uploading) { return { 'data-uploading': '' }; } return {}; }, }, }; }, addCommands() { return { ...this.parent?.(), // 自定义插入图片的命令,支持传入文件对象 insertUploadImage: (options) => ({ commands }) => { if (!options.file) return false; // 第一步:将文件转为base64插入编辑器 const reader = new FileReader(); reader.onload = (e) => { const base64Src = e.target.result; commands.insertImage({ src: base64Src, uploading: true, alt: options.file.name, }); // 第二步:异步上传图片,不阻塞用户操作 uploadImageToServer(options.file) .then((uploadedUrl) => { // 第三步:上传完成后替换base64为真实URL commands.updateAttributes('image', { src: uploadedUrl, uploading: false, }); }) .catch((err) => { // 上传失败添加错误标记 console.error('图片上传失败:', err); commands.updateAttributes('image', { uploading: false, 'data-error': 'upload-failed', }); }); }; reader.readAsDataURL(options.file); return true; }, }; }, }); // 替换为你的真实后台上传接口 async function uploadImageToServer(file) { const formData = new FormData(); formData.append('image', file); const response = await fetch('/api/upload-image', { method: 'POST', body: formData, }); if (!response.ok) throw new Error('上传失败'); const data = await response.json(); return data.url; }
二、在React组件中集成使用
在编辑器组件里注册自定义扩展,添加文件选择触发逻辑:
import { useEditor, EditorContent } from '@tiptap/react'; import { UploadImage } from './UploadImage'; import StarterKit from '@tiptap/starter-kit'; export default function TextEditor() { const editor = useEditor({ extensions: [ StarterKit, UploadImage, // 注册自定义图片扩展 ], content: '', }); // 处理文件选择 const handleImageUpload = (e) => { const file = e.target.files?.[0]; if (!file || !editor) return; // 调用自定义命令插入图片并触发上传 editor.commands.insertUploadImage({ file }); // 重置文件输入框 e.target.value = ''; }; return ( <div> <button onClick={() => document.getElementById('image-upload').click()}> 插入图片 </button> <input id="image-upload" type="file" accept="image/*" onChange={handleImageUpload} style={{ display: 'none' }} /> <EditorContent editor={editor} /> </div> ); }
三、可选:添加上传状态样式
通过CSS给上传中/失败的图片添加视觉提示:
img[data-uploading] { opacity: 0.7; position: relative; } img[data-uploading]::after { content: '上传中...'; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); background: rgba(0,0,0,0.5); color: white; padding: 4px 8px; border-radius: 4px; font-size: 12px; } img[data-error="upload-failed"] { border: 2px solid #ff4444; }
关键逻辑说明
- 插入图片时通过
FileReader快速转base64插入,避免用户等待 - 异步执行上传请求,不阻塞编辑器其他操作
- 上传完成后调用
updateAttributes替换图片地址,实时更新内容 - 上传失败时标记错误状态,方便用户识别处理
内容的提问来源于stack exchange,提问作者Saman
相关产品推荐
相关产品推荐

