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

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(() => {
    // 图片上传后的额外操作
  });
};

解决方向指引

  1. Promise时序问题:uploadImages()的Promise完成时,TinyMCE内部可能还未完成DOM更新,导致getContent()拿到的仍是旧内容。可在回调中加入微小延迟,或监听TinyMCE的NodeChange事件,确认内容更新后再获取。
  2. 状态更新异步性:React的setData是异步操作,手动调用onEditorChange后立即提交表单,可能状态还未更新完成。可改用useEffect监听data.body变化,待内容更新后再执行提交逻辑。
  3. TinyMCE配置冲突:同时设置images_upload_handler和images_upload_url可能导致逻辑冲突,建议只保留其中一个。另外automatic_uploads: false会关闭自动上传,需确保uploadImages()是唯一触发上传的入口。
  4. 手动替换准确性:手动替换base64时,result.blobInfo.base64()可能与编辑器中的base64字符串存在编码或格式差异(如换行符),建议改用result.blobInfo.blobUrl(),或直接通过编辑器DOM节点查找替换。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 20:52:05