我让 AI 封装了一个 ImageUpload 组件,它设计的 5 层校验链路比我想的周全

需求是"各种场景都要上传图片,但每次限制都不一样------有的要精确尺寸、有的要最小尺寸、有的要比例、有的要限格式限大小"。

我让 AI 设计这个组件的整体架构,它给出的"5 层校验管道"比我最初的方案好很多。我原本只想到 3 层。

需求场景

css 复制代码
场景 A(分类标签图):精确 150×90,≤50KB,仅 png
场景 B(分类顶部图):精确 789×96,≤100KB,jpg/png/gif
场景 C(商品主图):最小 750×750,≤2MB
场景 D(Banner):比例 16:9,≤500KB
场景 E(头像):任意尺寸,≤1MB

一个组件要覆盖所有场景,Props 设计是关键。

AI 设计的 5 层校验管道

我把需求描述给 AI 后,它提出了管道式校验架构:

typescript 复制代码
beforeUpload 执行顺序:
┌─────────────────────────────────────────┐
│ Layer 0: customBeforeUpload(用户自定义) │ ← 最高优先级
├─────────────────────────────────────────┤
│ Layer 1: validateType(格式校验)         │ ← accept: ['jpg','png']
├─────────────────────────────────────────┤
│ Layer 2: validateSize(体积校验)         │ ← maxSize + sizeUnit
├─────────────────────────────────────────┤
│ Layer 3: validateExactSize(精确尺寸)    │ ← limitRect: {w, h}
├─────────────────────────────────────────┤
│ Layer 4: validateMinSize(最小尺寸)      │ ← assertSize: {width, height}
├─────────────────────────────────────────┤
│ Layer 5: validateRatio(比例校验)        │ ← ratioLimit: {widthRatio, heightRatio}
└─────────────────────────────────────────┘
        │
        ↓ 全部通过
    开始上传

每一层独立、可选、互不干扰。不需要的校验层直接跳过(对应 prop 不传就行)。

我原本的方案 vs AI 的方案

kotlin 复制代码
我的方案(3 层):
├── 格式校验
├── 大小校验
└── 尺寸校验(一个函数里判断精确/最小/比例)
    └── 问题:逻辑耦合,后续加新校验类型要改这个函数

AI 的方案(5 层):
├── 每种校验独立函数
├── customBeforeUpload 作为逃生舱
├── 任意一层 return false 就中断
└── 优势:新增校验类型只需加一个函数,不改现有逻辑

AI 的方案更符合开放封闭原则------对扩展开放,对修改关闭。

核心实现

typescript 复制代码
const beforeUpload = async (file: File): Promise<any> => {
  // Layer 0: 自定义钩子
  if (customBeforeUpload) {
    const result = await customBeforeUpload(file)
    if (result === false) return Upload.LIST_IGNORE
  }

  // Layer 1: 格式
  if (!validateType(file)) return Upload.LIST_IGNORE

  // Layer 2: 体积
  if (!validateSize(file)) return Upload.LIST_IGNORE

  // Layer 3: 精确尺寸
  if (!(await validateExactSize(file))) return Upload.LIST_IGNORE

  // Layer 4: 最小尺寸
  if (!(await validateMinSize(file))) return Upload.LIST_IGNORE

  // Layer 5: 比例
  if (!(await validateRatio(file))) return Upload.LIST_IGNORE

  return file
}

注意 Layer 3-5 是 async 的------因为需要加载图片获取实际尺寸:

typescript 复制代码
const validateExactSize = async (file: File): Promise<boolean> => {
  if (!limitRect) return true  // 不传 prop 则跳过此层
  const objectURL = URL.createObjectURL(file)
  try {
    const img = await loadImage(objectURL)
    if (img.naturalWidth !== limitRect.w) {
      message.error(`图片宽度必须为 ${limitRect.w},当前为 ${img.naturalWidth}`)
      return false
    }
    if (img.naturalHeight !== limitRect.h) {
      message.error(`图片高度必须为 ${limitRect.h},当前为 ${img.naturalHeight}`)
      return false
    }
    return true
  } finally {
    URL.revokeObjectURL(objectURL)  // 防止内存泄漏
  }
}

使用时的简洁度

5 层校验,使用者只需要传对应的 prop:

tsx 复制代码
// 精确尺寸 + 体积限制
<ImageUpload limitRect={{w: 150, h: 90}} maxSize={50} sizeUnit="KB" />

// 最小尺寸
<ImageUpload assertSize={{width: 750, height: 750}} />

// 比例限制
<ImageUpload ratioLimit={{widthRatio: 16, heightRatio: 9}} maxSize={500} sizeUnit="KB" />

// 无校验(只限制数量)
<ImageUpload maxCount={3} />

AI 帮我发现的细节

在实现过程中,AI 还主动提出了几个我没想到的点:

  1. ObjectURL 必须手动释放------否则每次校验都会内存泄漏
  2. 视频和图片要分开处理 ------视频尺寸要用 <video> 元素获取,不能用 <img>
  3. fuzzy 模式------有时设计稿标注是"约 750px",需要容忍 ±2px 误差
  4. 多选时数量校验要提前------在校验尺寸之前就判断数量,避免无意义的图片加载

这些边界情况我如果自己写,大概率第一版会漏,线上出 bug 才补。

和 Form 的集成

maxCount=1 时,组件自动适配 Form.Item:

typescript 复制代码
value 接收:string(单张 URL)
onChange 返回:string | undefined

不需要 getValueFromEvent / getValueProps 转换。这个设计让使用侧代码简洁了很多:

tsx 复制代码
<Form.Item name="labelImage" label="分类标签图">
  <ImageUpload maxCount={1} limitRect={{w: 150, h: 90}} maxSize={50} sizeUnit="KB" />
</Form.Item>

零 adapter 代码。


💬 你们项目的图片上传是怎么处理校验的?有统一的组件还是每个页面各写各的?


🔗 完整 Skills 源码已开源 :github.com/sleepyccat/...,欢迎 Star ⭐ 和 PR。

相关推荐
奈落2421 分钟前
独立的AI编程助手正在消失?从文心快码并入百度搭子、Qwen Code转向CLI,看编程工具正被吸收进更大的智能体平台
百度·agent·ai编程·ai 编程
Chrischaan25 分钟前
做 AI 塔罗小程序时,我为什么不让大模型自己抽牌:一次上线复盘
前端
有毒的教程39 分钟前
Comfy Desktop下载安装教程-ComfyUI官方桌面版文生图模型配置与图像生成完整图文步骤
ai编程
寒狼GPT1 小时前
Codex 5小时额度是固定重置还是滚动恢复?为什么每个人Reset时间不一样
chatgpt·程序员·ai编程
libokaifa1 小时前
Claude Code Mods:给终端装一块自己的仪表盘
ai编程
骑着蜗牛撵大象3271 小时前
LangChain 工具调用从声明到闭环:给智能体接上真实的手脚
前端
用户721746588261 小时前
默认校验只覆盖 3.18%:bl dataset validate 抽样窗与 capability 三种返回态的字段级拆解
llm·agent·ai编程
数据掘金1 小时前
百度统计后台页面数据异常?从手动调用时机开始排查
前端
hunteritself1 小时前
10 层 4K 实时剪辑,国产工作站进入广电制作核心
大数据·前端·人工智能·深度学习·transformer
踩着两条虫1 小时前
我在浏览器里“盖”了一个村:Vue + Three.js 大屏开发踩坑记
前端·vue.js·three.js