Skip to content

TL;DR

  • 取消裁剪 ≠ 失败:用户放弃本次选择,应视为未选择,而不是上传失败。
  • 占位项策略:选择文件时先写入一条 uploading 占位;确认时就地改为 done失败改为 error取消移除占位
  • 校验触发:取消或完成后调用表单 onFieldChange(),让必填/失败规则即时生效。
  • 规则分治change 阶段只提示(warning),submit 阶段严格拦截(error)。

交互流转(状态机)

  1. 选择文件 → 写入占位:{ uid, name, status:'uploading', percent:0 }
  2. 弹出裁剪框
  3. 确认裁剪 → 压缩 → 上传成功:占位 就地更新 status:'done', url/thumbUrl, percent:100
  4. 上传失败:占位 就地更新 status:'error', response
  5. 取消裁剪移除占位,并触发表单校验(若必填则提示“请至少上传 1 张”)

校验最佳实践

目标:用户行为清晰,错误信息不重复、不误导。

  • 变更阶段(change

    • 仅对明确失败 errorwarning(不置红,不阻断)。
    • uploading(即便 percent=100)不报错。
  • 提交阶段(submit

    1. 若存在 error:报“上传失败”;
    2. 若存在 uploading:报“仍在上传,请稍候”;
    3. 若必填但无 done:报“请至少成功上传 1 张图片”。

配置上可在 Form.Item 开启 validateFirst,避免同周期多条错误叠加。


仅需调整的关键代码片段

1) 打开裁剪框前写入占位项

ts
// 复杂逻辑:写入 uploading 占位,UI/校验均能感知到“已选择”
_fileList.value = [
  ..._fileList.value.filter((f) => f.uid !== file.uid),
  {
    uid: file.uid,
    name: file.name,
    status: "uploading",
    percent: 0,
    originFileObj: file,
    url: "",
    thumbUrl: "",
  },
];

2) 确认裁剪成功后就地更新

ts
// 复杂逻辑:占位就地变更为成功
_fileList.value = _fileList.value.map((f) =>
  f.uid === uid ? { ...f, status: "done", url, thumbUrl: url, percent: 100 } : f
);
nextTick(() => ctx && ctx.onFieldChange());

3) 上传失败就地更新

ts
// 复杂逻辑:占位就地变更为失败(供 submit 阶段拦截)
_fileList.value = _fileList.value.map((f) =>
  f.uid === uid ? { ...f, status: "error", response: e.message } : f
);
nextTick(() => ctx && ctx.onFieldChange());

4) 取消裁剪时移除占位并校验

ts
// 复杂逻辑:取消裁剪=放弃本次选择,移除占位,触发必填校验
_fileList.value = _fileList.value.filter(
  (f) => f.uid !== selectedFile.value?.uid
);
URL.revokeObjectURL(imageUrl.value);
open.value = false;
selectedFile.value = null;
nextTick(() => ctx && ctx.onFieldChange());

5) Modal 右上角关闭也走取消逻辑

vue
<!-- 复杂逻辑:任意关闭动作都归一到 cancel -->
<a-modal v-model:open="open" @cancel="cancelCrop" />

文案与可用性建议

  • 取消不弹红色错误,最多给信息提示(如“已取消裁剪”)。

  • 失败要可读:来源(网络/格式/大小)+ 重试建议。

  • 体验细节

    • 始终 revokeObjectURL,避免内存泄漏;
    • 压缩失败可回退原图上传;
    • 占位项上显示微进度/Loading,让用户感知状态。

适配多文件/并发

  • 多文件独立 uid 管理,占位与就地更新一一对应;
  • 压缩/上传并发时,仍以 uid 精确更新,不互相污染;
  • 可加“清除失败项”入口(移除所有 status:'error' 的项)。

快速检查清单(Checklist)

  • [ ] 选择后立刻写入 uploading 占位
  • [ ] 确认/失败 就地更新,不新建条目
  • [ ] 取消 移除占位,并 onFieldChange()
  • [ ] change=warningOnlysubmit=error
  • [ ] validateFirst=true
  • [ ] revokeObjectURLfinally/取消 中调用

小结

这套方案把取消失败严格区分,既避免“误报失败”,又能在提交时可靠拦截未完成/未满足的情况;配合占位项与表单钩子,整体体验顺滑、实现简单、可维护性高。

本站总访问