如何修改DraftJS富文本编辑器实现全局拖拽图片上传?
解决DraftJS编辑器任意区域拖拽上传图片的问题
要实现编辑器任意区域拖拽上传,核心是给编辑器容器添加全局拖拽事件监听,拦截文件拖拽并复用现有上传逻辑,最后将图片插入到编辑器当前光标位置。以下是具体修改方案:
代码修改步骤
- 给编辑器外层容器添加
ref,用于绑定拖拽事件 - 实现拖拽事件处理函数,拦截文件并调用上传回调
- 上传完成后通过DraftJS API将图片插入到编辑器当前位置
修改后的完整代码
import React, { useState, useRef, useEffect } from 'react'; import { Editor, EditorState, convertToRaw } from 'draft-js'; import draftToHtml from 'draftjs-to-html'; const YourEditorComponent = (props) => { const [editorState, setEditorState] = useState(EditorState.createEmpty()); const editorContainerRef = useRef(null); const onEditorStateChange = (newState) => { setEditorState(newState); const htmlValue = draftToHtml(convertToRaw(newState.getCurrentContent())); setInputs({ id: props.id, value: htmlValue }); }; const uploadImageCallBack = (file) => { const imageObject = { file: file, localSrc: URL.createObjectURL(file), }; addImage(imageObject); return new Promise((resolve) => { resolve({ data: { link: imageObject.localSrc } }); }); }; // 处理拖拽上传逻辑 const handleDrop = async (e) => { e.preventDefault(); e.stopPropagation(); // 筛选出拖拽的图片文件 const imageFile = Array.from(e.dataTransfer.files).find(file => file.type.startsWith('image/') ); if (!imageFile) return; // 调用现有上传回调 const uploadResult = await uploadImageCallBack(imageFile); const imageUrl = uploadResult.data.link; // 将图片插入到编辑器当前光标位置 const contentState = editorState.getCurrentContent(); const contentWithImage = contentState.createEntity( 'IMAGE', 'IMMUTABLE', { src: imageUrl, alt: '' } ); const entityKey = contentWithImage.getLastCreatedEntityKey(); const newEditorState = EditorState.set(editorState, { currentContent: contentWithImage }); setEditorState( EditorState.insertText(newEditorState, null, ' ', null, entityKey) ); }; // 阻止默认拖拽行为,避免浏览器直接打开文件 const handleDragOver = (e) => { e.preventDefault(); e.stopPropagation(); }; const handleDragEnter = (e) => { e.preventDefault(); e.stopPropagation(); }; // 绑定/清理拖拽事件 useEffect(() => { const container = editorContainerRef.current; if (!container) return; container.addEventListener('dragenter', handleDragEnter); container.addEventListener('dragover', handleDragOver); container.addEventListener('drop', handleDrop); return () => { container.removeEventListener('dragenter', handleDragEnter); container.removeEventListener('dragover', handleDragOver); container.removeEventListener('drop', handleDrop); }; }, [editorState]); return ( <div ref={editorContainerRef}> <Editor editorState={editorState} onEditorStateChange={onEditorStateChange} readOnly={props.disabled} plugins={[dndFileUploadPlugin]} toolbar={{ image: { uploadCallback: uploadImageCallBack, previewImage: true, alt: { present: true, mandatory: false }, inputAccept: "image/gif,image/jpeg,image/jpg,image/png,image/svg", }, }} /> </div> ); }; export default YourEditorComponent;
关键说明
- 事件拦截:
handleDragEnter和handleDragOver必须阻止默认行为,否则浏览器会直接打开拖拽的文件 - 图片插入:通过DraftJS的
createEntity创建图片实体,再用insertText插入到当前光标位置 - 复用逻辑:直接调用现有
uploadImageCallBack,无需重新编写上传逻辑 - 内存管理:在
useEffect的清理函数中移除事件监听,避免内存泄漏
内容的提问来源于stack exchange,提问作者marry ximis
相关产品推荐
相关产品推荐

