layui图片上传需在choose回调中用obj.preview获取临时url,通过new image().onload异步读取宽高并校验比例,设auto:false阻止自动上传,用浮点误差容忍(±0.05)比对目标比例。
choose 回调里用 img.onload 读取原始宽高
layui 本身不提供“限制图片比例”的原生参数,必须在 choose 回调中手动预览并校验。关键在于用 obj.preview 拿到图片的 result(base64 或 blob url),再通过 new image() 加载后读取 width 和 height。
注意:img.onload 是异步的,不能直接 return 布尔值控制流程;必须在 onload 内部调用 obj.upload() 或弹窗拦截 —— 否则会跳过校验直接上传。
- 一定要设
auto: false,否则图片选完就自动发请求,根本没机会校验 -
obj.preview的result是浏览器生成的临时地址,兼容性好,比 FileReader 更稳 - 部分老旧安卓 WebView 可能不触发 onload,可加超时兜底(如 setTimeout 2s 后报错)
按宽高比计算并拦截不符合的图片
拿到 img.width 和 img.height 后,用浮点除法算比例,再和目标比例(如 4:3 → 1.333,16:9 → 1.777)比对。建议用误差容忍(±0.05),避免因四舍五入或像素微差误判。
示例:要求必须是 1:1 正方形图
obj.preview(function(index, file, result){
var img = new Image();
img.src = result;
img.onload = function() {
var ratio = img.width / img.height;
if (Math.abs(ratio - 1) > 0.05) {
layer.msg('请上传正方形图片(宽高比 1:1)');
return;
}
obj.upload(index, file);
};
});
- 别用
==直接比较浮点数,比如img.width/img.height === 16/9会失败 - 如果要求“宽高比 ≤ 16:9”,应写成
ratio ,而非只判断是否等于 - 用户一次选多张图时,
obj.preview会逐个触发,每张都独立校验
服务端仍需复核比例,前端校验可被绕过
用户禁用 JS、篡改 DOM 或用 curl 上传时,前端比例校验完全失效。服务端必须用图像库(如 Python 的 Pillow、PHP 的 GD)重新 decode 并计算真实宽高比。
- 前端只负责体验优化和快速反馈,不是安全边界
- 尤其注意:某些 PNG 图片带 orientation 信息,浏览器渲染时自动旋转,但原始宽高未变 —— 服务端读取的是原始尺寸,前后端判断逻辑要一致
- 若业务强依赖比例(如证件照排版),建议服务端校验后返回具体错误码,前端据此提示“宽高比不符,实际为 X:X”
避免常见坑:预览失败、跨域、大图卡顿
obj.preview 在某些场景下可能不触发 onload,比如:
- 文件类型非标准图片(如 .webp 在旧版 Safari 不支持)→ 先用
file.type.startsWith('image/')过滤 - 图片损坏或编码异常 → 加
img.onerror处理,提示“图片无法预览,请检查格式” - 单张图超 5MB,加载慢甚至中断 → 可加 loading 提示,或限制
size: 5120(5MB)作为前置门槛 - HTTPS 页面加载 HTTP 图片(混合内容)→ 确保
result协议与当前页一致,必要时用URL.createObjectURL(file)替代
比例校验这事,前端能拦住大部分误操作,但真要守住底线,得前后端各算一遍 —— 少一个,上线后就可能收到运营哭诉:“用户上传的横图被裁成竖图了”。











