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

Vue.js无库实现图片上传至MongoDB报错求助

问题分析与修复方案

错误原因拆解

1. 选择图片后立即报错

给type="file"的输入框绑定v-model="skillData.image"会触发报错,因为File对象是只读的,Vue的双向绑定机制会尝试修改这个只读对象,导致浏览器抛出"Failed to set the 'value' property on 'HTMLInputElement'"类错误。

2. 提交表单后报错

  • 验证阶段(validateData)时,skillData.image是File对象,如果skillSchema的验证规则是针对字符串(base64)设计的,会直接验证失败。
  • 提交前直接覆盖skillData.value.image为base64字符串,可能导致后续依赖File对象的逻辑(比如二次验证)出错。
  • file类型输入框的@input事件触发时机不合理,会频繁触发resetError逻辑,干扰正常流程。

具体修复步骤

1. 移除file输入框的v-model绑定

file类型输入不支持Vue的双向绑定,直接通过@change事件处理文件选择:

<form-input-molecule
  label="Image"
  id="image"
  name="image"
  type="file"
  :error-message="validationErrors.skillCreationForm?.image"
  @change="previewImage"
></form-input-molecule>

2. 分离验证与提交的数据处理

验证时使用原始File对象,提交前再转换为base64,避免覆盖原始数据:

const createSkill = async () => {
  try {
    validationErrors.value["skillCreationForm"] = {};
    // 用原始File对象做验证
    const isValid = await validateData(
      ["skillCreationForm"],
      skillSchema,
      skillData.value
    );
    if (!isValid) return;
    
    // 单独转换base64,不修改原skillData
    const imageBase64 = await toBase64(skillData.value.image);
    const submitData = {
      ...skillData.value,
      image: imageBase64,
      progress: parseInt(skillData.value.progress)
    };
    
    await skillStore.createSkill(submitData);
    router.push({ name: "skills" });
  } catch (error) {
    console.error(error);
  }
};

3. 适配skillSchema的File对象验证规则

如果使用Yup做验证,需要针对File对象编写格式校验:

// skillSchema示例
import * as yup from 'yup';

export const skillSchema = yup.object().shape({
  name: yup.string().required('名称必填'),
  image: yup.mixed()
    .required('图片必填')
    .test('file-type', '仅支持JPG/PNG/GIF格式', (value) => {
      return value && ['image/jpeg', 'image/png', 'image/gif'].includes(value.type);
    }),
  progress: yup.number().min(0).max(100).required('进度必填')
});

4. 清理预览URL避免内存泄漏

组件卸载时释放createObjectURL创建的临时URL:

import { onUnmounted } from 'vue';

let currentPreviewUrl = null;

const previewImage = (event) => {
  const preview = document.getElementById("preview-image");
  skillData.value.image = event.target.files[0];
  
  if (skillData.value.image) {
    // 先释放旧的预览URL
    if (currentPreviewUrl) URL.revokeObjectURL(currentPreviewUrl);
    currentPreviewUrl = URL.createObjectURL(skillData.value.image);
    preview.src = currentPreviewUrl;
  } else {
    preview.src = "";
  }
};

// 组件销毁时清理资源
onUnmounted(() => {
  if (currentPreviewUrl) URL.revokeObjectURL(currentPreviewUrl);
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 13:51:29