ReactJS中Draft wysiwyg编辑器如何保存图文内容到服务器
实现Draft-Wysiwyg文本+图片共同存到服务端的方案
核心要解决两个问题:
- 图片不能只用本地blob临时地址,必须先上传到你的存储服务/服务端拿到永久可访问的URL
- 不能只提取纯文本,要把富文本内容序列化为可传输的格式(推荐HTML或者Draft原始Raw格式)
第一步:改造TextEditor类组件
需要做三个改动:
- 图片上传回调里,把选中的图片文件先传到服务端,拿到返回的线上图片URL再回显,不要用本地临时地址
- 新增获取富文本内容的方法,供父组件调用拿完整内容
- 修正原有配置错误:原来的
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
相关产品推荐
相关产品推荐

