Layui upload 上传前读取图片分辨率需在 choose 回调中用 obj.preview 获取 base64,再通过 new Image() 加载并监听 onload,读取 naturalWidth/naturalHeight;必须配合 auto: false 使用,且服务端须二次校验。
layui upload 上传前怎么读取图片分辨率
直接用 obj.preview 拿到 base64 地址,再用 new image() 加载并监听 onload,就能拿到 img.width 和 img.height。这是唯一可行的前端方案,layui 本身不提供内置分辨率校验。
注意:这个过程依赖浏览器解码能力,webp、heic 等格式在 Safari 或旧版 Chrome 中可能加载失败或返回 0;大图(>5MB)加载慢,用户会明显卡顿;obj.preview 必须配合 auto: false 使用,否则还没校验就自动上传了。
-
auto: false是前提,否则choose回调里无法拦截 -
obj.preview的result是 base64 字符串,可直接赋给img.src - 别在
before钩子里做这事——它没提供文件预览能力 - 加载失败时,
img.naturalWidth/img.naturalHeight可能为 0,需加兜底判断
如何写一个可靠的宽高校验逻辑
不要只比对固定值(比如必须是 600x800),多数业务要的是范围或比例。常见写法是提取关键条件后统一判断,避免嵌套过深。
示例:要求图片短边 ≥ 300px,长边 ≤ 4096px,且宽高比在 0.5~2 之间:
choose: function(obj) {
obj.preview(function(index, file, result) {
var img = new Image();
img.onload = function() {
var w = this.naturalWidth || this.width;
var h = this.naturalHeight || this.height;
var ratio = Math.max(w, h) / Math.min(w, h);
<pre class="brush:php;toolbar:false;"> if (Math.min(w, h) 4096 || ratio > 2) {
layer.msg('图片尺寸不符合要求:短边≥300px,长边≤4096px,宽高比≤2');
return;
}
obj.upload(index, file);
};
img.onerror = function() {
layer.msg('图片无法解析,请检查格式');
};
img.src = result;}); }
- 优先用
naturalWidth/naturalHeight,更准确;fallback 到width/height - 一定要写
img.onerror,否则损坏图或不支持格式会静默失败 - 校验失败时不能只
return false,得显式不调用obj.upload()
为什么不能只靠前端限制分辨率
用户禁用 JS、绕过选择框(如直接 POST 表单)、改后缀伪装图片,都能跳过前端校验。Layui 的 choose 回调完全运行在客户端,服务端收不到任何“已校验”信号。
- 服务端必须用图像库(如 PHP 的
getimagesize()、Node.js 的sharp、Python 的PIL)重新读取原始文件并校验像素 - 前端校验只是体验优化,不是安全措施
- 如果业务允许裁剪,建议前端只校验最小尺寸(防糊图),裁剪逻辑交给服务端或前端 canvas
视频文件的分辨率怎么限制
Layui upload 不支持直接读取视频帧或元信息,video 标签的 videoWidth/videoHeight 在部分浏览器(尤其是 Safari)中不可靠,且大视频加载极慢。
- 前端仅建议做轻量级拦截:先用
accept: 'video'+exts过滤后缀,再用video标签尝试加载首帧(设preload: 'metadata') - 但必须接受失败率——某些编码格式(如 H.265、AV1)或容器(如 MKV)可能无法触发
onloadedmetadata - 真正可靠的方案是服务端用
ffprobe解析,返回宽高后再决定是否入库 - 别在 choose 里循环处理多个视频文件——单个视频加载卡住会阻塞整个队列
最易被忽略的点:所有基于 preview 的校验都依赖 base64 数据,而 base64 编码会让内存占用翻倍,10MB 图片在内存里可能占 15MB+。移动端尤其容易 OOM,务必加大小兜底(比如 file.size > 8 * 1024 * 1024 就跳过预览直接报错)。











