draftjs编辑器中按退格键删除图片时如何同步删除数据库对应资源
DraftJS编辑器删除图片时同步清理数据库资源的实现方案
核心实现逻辑
- 给图片绑定唯一资源标识:图片上传到后端存储成功后,除了返回图片访问URL,后端需要同步返回该资源的全局唯一ID,将ID和URL共同存入DraftJS自定义图片原子块的
entity数据中,避免仅依赖URL判断出现重复URL误删的问题。创建图片entity的示例代码如下:const imageEntityKey = Entity.create( 'CUSTOM_IMAGE', 'IMMUTABLE', { url: 'https://your-cdn.com/xxx.jpg', resourceId: 'img_123456abcdef' } ) - 监听编辑器内容变更:通过DraftJS原生提供的
onChange回调,每次内容更新时拿到最新的EditorState实例。 - 对比图片ID差集:每次内容变更时,分别提取上一次编辑器状态和当前最新状态中所有图片的
resourceId,二者的差集即为用户刚刚删除的图片资源ID。 - 防抖调用删除接口:拿到被删除的资源ID列表后,加300~500ms的防抖调用后端资源删除接口,避免用户频繁操作时产生大量无效请求,同时兼容用户误删后马上撤销的场景,避免不必要的资源删除。
边缘情况兜底处理
- 适配撤销/重做操作:每次
onChange触发时同步更新存储的历史图片ID列表,无需额外处理撤销重做逻辑,差集计算逻辑会自动适配状态回退的场景,若用户撤销删除操作,对应ID会重新出现在最新ID列表中,不会触发删除。 - 临时资源标记:未正式提交的草稿关联的图片资源需要打临时标记,只有用户确认删除草稿、或草稿超过7天未编辑时再清理对应资源,避免用户编辑中途退出后重新进入草稿出现图片丢失的问题。
- 后台定时清理:作为前端监听逻辑的兜底,后端可每日定时扫描所有未被任何正式内容、有效草稿关联的图片资源,统一清理,避免极端场景下的垃圾数据残留。
核心实现代码示例
import { useState, useRef } from 'react'; import { Editor, EditorState, convertToRaw } from 'draft-js'; import debounce from 'lodash/debounce'; const DraftEditor = () => { const [editorState, setEditorState] = useState(() => EditorState.createEmpty()); // 存储上一次编辑器内容中的图片资源ID列表 const lastImgIds = useRef([]); // 提取指定EditorState中所有图片的资源ID const getAllImgResourceIds = (state) => { const contentState = state.getCurrentContent(); const rawBlocks = convertToRaw(contentState).blocks; const idList = []; rawBlocks.forEach(block => { block.entityRanges.forEach(range => { const entity = contentState.getEntity(range.key); if (entity.getType() === 'CUSTOM_IMAGE') { idList.push(entity.getData().resourceId); } }) }) return idList; }; // 防抖调用删除接口 const deleteImageResources = debounce(async (deletedIds) => { await fetch('/api/image/delete', { method: 'POST', body: JSON.stringify({ resourceIds: deletedIds }) }) }, 400); const handleEditorChange = (newState) => { setEditorState(newState); const newImgIds = getAllImgResourceIds(newState); // 计算被删除的资源ID const deletedIds = lastImgIds.current.filter(id => !newImgIds.includes(id)); if (deletedIds.length) { deleteImageResources(deletedIds); } // 更新存储的ID列表 lastImgIds.current = newImgIds; }; return <Editor editorState={editorState} onChange={handleEditorChange} /> };
内容的提问来源于stack exchange,提问作者Lucas Abrantes
相关产品推荐
相关产品推荐

