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

ReactJS中Draft wysiwyg编辑器如何保存图文内容到服务器

实现Draft-Wysiwyg文本+图片共同存到服务端的方案

核心要解决两个问题:

  • 图片不能只用本地blob临时地址,必须先上传到你的存储服务/服务端拿到永久可访问的URL
  • 不能只提取纯文本,要把富文本内容序列化为可传输的格式(推荐HTML或者Draft原始Raw格式)

第一步:改造TextEditor类组件

需要做三个改动:

  1. 图片上传回调里,把选中的图片文件先传到服务端,拿到返回的线上图片URL再回显,不要用本地临时地址
  2. 新增获取富文本内容的方法,供父组件调用拿完整内容
  3. 修正原有配置错误:原来的inputAccept写在image配置外不会生效,要移到image配置项内

改完的组件代码如下:

import { EditorState, convertToRaw } from 'draft-js';
import { Editor } from 'react-draft-wysiwyg';
import draftToHtml from 'draftjs-to-html'; 
// 先安装依赖:`npm i draftjs-to-html`
import React, { Component } from 'react';

class TextEditor extends Component {
  constructor(props) {
    super(props);
    this.state = {
      editorState: EditorState.createEmpty(),
    };
  }

  onEditorStateChange = (editorState) => {
    this.setState({ editorState });
    // 需要实时同步内容给父组件可打开下方注释
    // const content = draftToHtml(convertToRaw(editorState.getCurrentContent()));
    // this.props.onContentChange?.(content);
  };

  // 图片上传逻辑,替换为你自己的服务端上传接口
  _uploadImageCallBack = (file) => {
    return new Promise((resolve, reject) => {
      const formData = new FormData();
      formData.append('file', file);
      
      // 替换为你自己的上传接口地址
      fetch('/your-server-upload-api', {
        method: 'POST',
        body: formData,
      })
      .then(res => res.json())
      .then(res => {
        // 根据接口实际返回结构调整,最终要拿到图片的可访问线上URL
        resolve({
          data: {
            link: res.data.url
          }
        });
      })
      .catch(err => reject(err));
    });
  };

  // 暴露给父组件的方法:返回完整富文本内容(文本+图片)
  getEditorContent = () => {
    const { editorState } = this.state;
    const rawContent = convertToRaw(editorState.getCurrentContent());
    return {
      raw: rawContent, // Draft原生结构,后续回显编辑器用这个兼容性更好
      html: draftToHtml(rawContent) // 带<img>标签的HTML内容,前端直接渲染展示用
    };
  };

  render() {
    const { editorState } = this.state;
    return (
      <div style={{ height: "100%", width: "100%" }}>
        <Editor
          editorState={editorState}
          toolbarClassName='toolbarClassName'
          wrapperClassName='wrapperClassName'
          editorClassName='editorClassName'
          onEditorStateChange={this.onEditorStateChange}
          toolbar={{
            inline: { inDropdown: true },
            list: { inDropdown: true },
            textAlign: { inDropdown: true },
            link: { inDropdown: true },
            history: { inDropdown: true },
            image: { 
              uploadCallback: this._uploadImageCallBack,
              alt: { present: true, mandatory: false }
            },
            inputAccept: "image/*,application/pdf,text/plain,application/vnd.openxmlformats-officedocument.wordprocessingml.document,application/msword,application/vnd.ms-excel",
          }}
        />
      </div>
    );
  }
}

export default TextEditor;

你之前代码里维护的uploadedImages数组没有实际作用,图片上传成功后编辑器会自动把对应<img>标签插入内容,不需要单独维护图片列表


第二步:在父函数组件中提交内容到服务端

通过ref拿到TextEditor实例,提交时调用暴露的getEditorContent方法拿到完整内容,再发送给服务端即可:

import React, { useRef } from 'react';
import TextEditor from './TextEditor';

export default function FormPage() {
  const editorRef = useRef(null);

  const handleSubmit = async () => {
    // 拿到包含文本、图片地址的完整富文本内容
    const editorContent = editorRef.current.getEditorContent();
    // 提交到服务端
    await fetch('/your-save-content-api', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        // 其他表单字段...
        contentHtml: editorContent.html,
        contentRaw: editorContent.raw
      })
    });
    // 后续提交成功逻辑
  };

  return (
    <div>
      {/* 其他表单组件 */}
      <TextEditor ref={editorRef} />
      <button onClick={handleSubmit}>提交内容</button>
    </div>
  );
}

补充说明

  • 优先存储raw字段的JSON结构,后续回显编辑器时用Draft自带的convertFromRaw方法转成ContentState即可,不会丢失格式;如果只需要前端展示内容,存html字段更方便
  • 上传接口返回的图片URL必须保证在业务场景下可正常访问,否则内容里的图片会加载失败

内容的提问来源于stack exchange,提问作者fq sof

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 04:01:18