如何将Draft.js富文本内容携带样式发送至MongoDB存储
富文本内容存取MongoDB实现方案
核心问题定位
- 现有
TextEditor组件未将富文本内容透传给父组件,父组件绑定的onChange是原生输入框的取值逻辑,无法获取富文本的格式化内容 - 序列化/反序列化方法调用位置错误:
convertToRaw要在编辑器内容更新、提交给后端前调用,convertFromRaw要在从后端拿到存储内容、回显渲染时调用 - 现有Mongoose模型无需修改,
String类型完全支持存储序列化后的富文本内容
分步修改代码
1. 修改TextEditor组件,向外同步编辑内容
在编辑器状态更新的回调里,除了更新组件自身state,同时把序列化后的内容通过props传递给父组件。
两种存储模式二选一即可:
- 模式1:存储Draft.js原生Raw JSON:无损保留所有编辑状态,后续支持二次编辑富文本
- 模式2:存储转换后的HTML字符串:存储后直接渲染即可,不需要二次转换,适合仅展示场景
修改后的TextEditor.js代码:
import React, { Component } from "react"; import { Editor } from "react-draft-wysiwyg"; import { EditorState, convertToRaw } from "draft-js"; import "react-draft-wysiwyg/dist/react-draft-wysiwyg.css"; import draftToHtml from "draftjs-to-html"; export default class TextEditor extends Component { state = { editorState: EditorState.createEmpty(), }; onEditorStateChange = (editorState) => { this.setState({ editorState, }); // 内容变化时同步给父组件 const contentState = editorState.getCurrentContent(); // --- 模式1:存Raw JSON 用下面这行--- const contentValue = JSON.stringify(convertToRaw(contentState)); // --- 模式2:存HTML 用下面这行,二选一--- // const contentValue = draftToHtml(convertToRaw(contentState)); // 调用父组件传入的onChange回传内容 this.props.onChange(contentValue); }; render() { const { editorState } = this.state; return ( <div> <Editor editorState={editorState} toolbarClassName="toolbarClassName" wrapperClassName="wrapperClassName" editorClassName="editorClassName" onEditorStateChange={this.onEditorStateChange} placeholder={this.props.placeholder} /> {/* 不需要预览可以删掉下面的textarea */} <textarea disabled value={draftToHtml(convertToRaw(editorState.getCurrentContent()))} ></textarea> </div> ); } }
2. 修改Write.jsx页面,正确接收富文本内容提交
TextEditor不是原生表单元素,不会返回标准event对象,直接接收子组件回传的内容赋值即可。
修改后的Write.jsx代码:
import { useState, useContext } from 'react'; import axios from 'axios'; import TextEditor from '../../components/TextEditor/TextEditor'; import { Context } from '../../context/Context'; // 替换为你项目的Context实际引入路径 export default function Write() { const [desc, setDesc] = useState(''); const { user } = useContext(Context); const handleSubmit = async (e) => { e.preventDefault(); const newPost = { username: user.username, desc, // 这里拿到的就是序列化好的富文本内容,直接提交即可 }; try { const res = await axios.post('/posts', newPost); window.location.replace('/post/' + res.data._id); } catch (err) { console.log(err); } }; return ( <div className='write'> <form className='writeForm' onSubmit={handleSubmit}> <TextEditor placeholder='Write your story' className='writeInput writeText' // 直接接收子组件回传的内容,不需要e.target.value onChange={(value) => setDesc(value)} /> <button className='writeSubmit' type='submit'> نشر </button> </form> </div> ); }
注意:原代码缺少
useState、useContext的引入,Context的引入路径需要替换为项目实际路径,否则会运行报错。
3. 读取内容渲染(详情页使用)
根据之前选择的存储模式,对应渲染即可:
- 如果选的模式2(存HTML):直接把从接口拿到的
desc字段渲染到页面即可,示例:<div className="postContent" dangerouslySetInnerHTML={{__html: post.desc}}></div> - 如果选的模式1(存Raw JSON):需要先反序列化再转换,既支持回显到富文本编辑器二次编辑,也可以转成HTML渲染:
import { convertFromRaw, EditorState } from 'draft-js'; import draftToHtml from 'draftjs-to-html'; // 接口拿到desc后处理 const rawContent = JSON.parse(post.desc); const contentState = convertFromRaw(rawContent); // 转HTML直接渲染 const htmlContent = draftToHtml(rawContent); // 回显到编辑器做二次编辑用 const editorState = EditorState.createWithContent(contentState);
补充说明
现有Post.js Mongoose模型不需要修改,desc字段设为String类型可以正常存储两种格式的富文本内容,不会出现样式丢失问题。
内容的提问来源于stack exchange,提问作者sultan.h
相关产品推荐
相关产品推荐

