You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何修改DraftJS富文本编辑器实现全局拖拽图片上传?

解决DraftJS编辑器任意区域拖拽上传图片的问题

要实现编辑器任意区域拖拽上传,核心是给编辑器容器添加全局拖拽事件监听,拦截文件拖拽并复用现有上传逻辑,最后将图片插入到编辑器当前光标位置。以下是具体修改方案:

代码修改步骤

  1. 给编辑器外层容器添加ref,用于绑定拖拽事件
  2. 实现拖拽事件处理函数,拦截文件并调用上传回调
  3. 上传完成后通过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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 18:50:26