TinyMCE上传图片src属性未替换,表单提交报错求助
问题:TinyMCE图片上传后src未替换导致表单提交失败
使用TinyMCE官方图片插件,基于React+Laravel+InertiaJS技术栈,图片能正常上传至后端,但首次提交表单时会触发后端校验报错——原因是<img>标签的src仍为base64格式字符串,导致请求内容长度超出65535字符限制。奇怪的是,提交失败后src会自动替换为后端返回的地址,此时表单可正常提交。
当前逻辑为:图片先以blob形式存于本地,用户提交表单时上传至服务器,期望TinyMCE自动将src替换为后端返回的地址。尝试过手动更新body状态、用Promise返回的URL替换base64字符串,均未解决问题。调试发现调用uploadImages()后onEditorChange函数不会自动触发,即使手动调用该函数更新状态,body数据仍无变化。
提交函数初始实现
const submit = (e) => { e.preventDefault() editorRef.current.uploadImages().then((uploadResults) => { if (!memory) { post(route('memory'), { onSuccess: handleSuccess, onError: (errors) => { console.error(Object.values(errors)) handleError() } }) } else { post(route('memory.update', { slug: memory.slug }), { onSuccess: handleSuccess, onError: (errors) => { console.error(errors) handleError() } }) } }) } const handleSuccess = () => { toast({ title: <Check className="text-blue-500"/>, description: !memory ? t('apiResponse.success.add') : t('apiResponse.success.text'), }) } const handleError = () => { toast({ title: t('apiResponse.error.title') }) }
手动更新状态的尝试
async function uploadImages() { const results = await editorRef.current.uploadImages(); const body = data.body; // 复制当前状态 for (const result of results) { if (result.status === true) { const imageUrl = result.uploadUri; updatedBody = updatedBody.replace(result.blobInfo.base64(), imageUrl); } } setData('body', updatedBody); return results.map(result => result.status === true); }
调用方式:
const submit = async (e) => { e.preventDefault(); try { const uploadResults = await uploadImages(); if (uploadResults.every(value => value)) { if (typeof memory === 'undefined') { post(route('memory'), { onSuccess: handleSuccess }); } else { patch(route('memory.update', { slug: memory.slug }), { onSuccess: handleSuccess }); } } else { toast({ title: t('apiResponse.error.title') }); } } catch (error) { console.error('Error during image uploads:', error); } };
TinyMCE配置
<Editor init={{ file_picker_types: 'image', relative_urls: false, remove_script_host: false, document_base_url: '../', images_upload_handler: handleImageUpload, images_upload_url: route('file.store'), automatic_uploads: false, }} /> const handleImageUpload = (blobInfo, progress) => new Promise((resolve, reject) => { const formData = new FormData() formData.append('file', blobInfo.blob()) axios.post(route('file.store'), formData, { onUploadProgress: ({loaded, total}) => { progress(Math.round((loaded * 100) / total)) }, withXSRFToken: true, }).then((response) => { const { location } = response.data resolve(location) }).catch((error) => { console.error('Error:', error) reject(error.response.data.location) }) })
onEditorChange不触发问题
调试发现调用uploadImages()后onEditorChange不会自动触发,手动调用更新状态也无效。组件集成方式:
<TinyEditorComponent onInit={(evt, editor) => (editorRef.current = editor)} init={{ content_style: 'body { font-size:14px };', height: '100vh', }} onEditorChange={onEditorChange} initialValue={text} />
onEditorChange实现:
const onEditorChange = (newContent) => { setData('body', newContent); console.log("Body changed:", newContent); };
目前临时处理方案:
const submit = (e) => { e.preventDefault(); editorRef.current.uploadImages().then((uploadResults) => { const updatedContent = editorRef.current.getContent(); onEditorChange(updatedContent); }).then(() => { // 图片上传后的额外操作 }); };
解决方向指引
- Promise时序问题:
uploadImages()的Promise完成时,TinyMCE内部可能还未完成DOM更新,导致getContent()拿到的仍是旧内容。可在回调中加入微小延迟,或监听TinyMCE的NodeChange事件,确认内容更新后再获取。 - 状态更新异步性:React的
setData是异步操作,手动调用onEditorChange后立即提交表单,可能状态还未更新完成。可改用useEffect监听data.body变化,待内容更新后再执行提交逻辑。 - TinyMCE配置冲突:同时设置
images_upload_handler和images_upload_url可能导致逻辑冲突,建议只保留其中一个。另外automatic_uploads: false会关闭自动上传,需确保uploadImages()是唯一触发上传的入口。 - 手动替换准确性:手动替换base64时,
result.blobInfo.base64()可能与编辑器中的base64字符串存在编码或格式差异(如换行符),建议改用result.blobInfo.blobUrl(),或直接通过编辑器DOM节点查找替换。
内容的提问来源于stack exchange,提问作者Aiphton
相关产品推荐
相关产品推荐

