唯一可行路径是在choose回调中调用obj.preview()获取base64,用new image()加载并监听onload,通过naturalwidth/naturalheight读取真实像素值,且必须设auto: false。

choose 回调里用 obj.preview 读取 base64 再加载 Image
前端限制图片物理分辨率,唯一可行路径是在 choose 回调中调用 obj.preview() 获取 base64 字符串,再用 new Image() 加载并监听 onload,从 naturalWidth/naturalHeight 读真实像素值。Layui 本身不提供内置宽高校验,这个过程必须手动实现。
关键前提:必须设 auto: false,否则文件选中后立即上传,根本没机会校验。别在 before 钩子做这事——它收不到 result,也没法预览。
-
obj.preview()的result是 base64 字符串,可直接赋给img.src - 务必用
this.naturalWidth || this.width取值,某些浏览器(如旧版 Safari)对 WebP/HEIC 返回 0 - 必须写
img.onerror,否则损坏图、不支持格式会静默失败,用户卡住无提示 - 校验失败时不能只
return,得显式不调用obj.upload(),否则照样上传
宽高判断逻辑要防浮点误差和方向颠倒
不要写 if (w === 600 && h === 800) 这种硬匹配,业务需求通常是范围或比例。比如“短边 ≥ 300px,长边 ≤ 4096px,宽高比在 0.5~2 之间”,就得提取共性后统一判断。
- 用
Math.min(w, h)和Math.max(w, h)统一处理横竖图,避免单独判断方向 - 算宽高比时用
Math.max(w, h) / Math.min(w, h),再和目标值比较绝对差,容忍阈值设 0.01 - 别依赖
file.width/file.height——File 对象根本没有这两个属性 - 大图(>5MB)加载慢,用户会明显卡顿,建议加 loading 提示或降级为服务端校验
多图场景下必须 Promise.all 控制并发
一次选多个文件时,obj.preview() 会为每个文件触发一次回调,但图片加载是异步的。如果在循环里直接调用 obj.upload(),顺序错乱、部分文件丢失、甚至重复上传都可能发生。
- 先用
Object.keys(obj.files)拿到安全索引数组,别用for...in遍历对象 - 每个文件压缩或校验封装成 Promise,收集进数组,最后
Promise.all(promises)统一处理 - 任一失败应 fallback 到原图上传(
obj.upload(index, files[index])),避免整批中断 - 切记:Layui 不感知你对
File对象做的任何内存修改,必须靠obj.resetFile()显式写入才生效
服务端二次校验不可省略
前端校验能提升体验,但完全不可信。用户禁用 JS、绕过选择框(如直接 POST 表单)、改后缀伪装图片,都能跳过所有前端逻辑。choose 回调纯运行在客户端,服务端收不到任何“已校验”信号。
最易被忽略的是:哪怕你用 canvas 压缩、用 Image 解析、用 layer.msg 提示,只要服务端没做独立宽高校验,攻击者就能传任意尺寸的图进来。尤其注意 WebP/HEIC 等格式在 Safari 中解析失败,前端返回 0 值,若服务端不兜底,就等于放行了非法图。











