本文提供 3 套完整方案 (原生 Canvas、轻量级库、批量脚本),全部 零后端依赖 ,支持 WebP、JPEG、PNG、GIF,可直接搬进项目。
1️⃣ 方案 A:原生 Canvas 压缩(零依赖)
1.1 核心 30 行函数
js
/**
* 将 File 压缩成 Blob
* @param {File} file 原文件
* @param {Object} opts 配置
* maxWidth: 最大宽度(px)
* maxHeight:最大高度(px)
* quality: JPEG/WebP 质量 0-1
* @returns {Promise<Blob>} 压缩后 Blob
*/
async function compressImage(file, opts = {}) {
const { maxWidth = 800, maxHeight = 600, quality = 0.8 } = opts;
return new Promise((resolve, reject) => {
const img = new Image();
img.onload = () => {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
// 等比缩放
let { width, height } = img;
if (width > maxWidth || height > maxHeight) {
const scale = Math.min(maxWidth / width, maxHeight / height);
width *= scale;
height *= scale;
}
canvas.width = width;
canvas.height = height;
ctx.drawImage(img, 0, 0, width, height);
canvas.toBlob(resolve, file.type === 'image/png' ? 'image/png' : 'image/jpeg', quality);
};
img.onerror = reject;
img.src = URL.createObjectURL(file);
});
}
1.2 调用示例
html
<input type="file" id="file" accept="image/*" />
<button onclick="handle()">压缩并预览</button>
<canvas id="canvas" style="border:1px solid #000;max-width:100%;"></canvas>
<script>
async function handle() {
const file = document.getElementById('file').files[0];
if (!file) return;
const blob = await compressImage(file, { maxWidth: 800, quality: 0.7 });
const url = URL.createObjectURL(blob);
document.getElementById('canvas').src = url;
console.log(`压缩前 ${(file.size/1024).toFixed(1)}KB → 压缩后 ${(blob.size/1024).toFixed(1)}KB`);
}
</script>
压缩前 | 压缩后 | 压缩率 |
---|---|---|
3.2 MB | 315 KB | 90% |
2️⃣ 方案 B:Compressor.js 一行搞定(推荐)
html
<script src="https://cdn.jsdelivr.net/npm/compressorjs@1.2.1/dist/compressor.min.js"></script>
<input type="file" id="uploader" accept="image/*" multiple />
<script>
document.getElementById('uploader').addEventListener('change', e => {
Array.from(e.target.files).forEach(file => {
new Compressor(file, {
quality: 0.7,
maxWidth: 1024,
maxHeight: 1024,
convertSize: 500000, // >500KB 转 WebP
success(result) {
console.log(`${(file.size/1024).toFixed(1)}KB → ${(result.size/1024).toFixed(1)}KB`);
// 可直接 `fetch('/upload', { method:'POST', body: result })`
},
error(err) {
alert(err.message);
}
});
});
});
</script>
3️⃣ 方案 C:批量脚本(Node CLI)
3.1 安装依赖
bash
npm i -D imagemin imagemin-mozjpeg imagemin-pngquant imagemin-webp
3.2 一键压缩目录
js
// compress.js
import imagemin from 'imagemin';
import imageminMozjpeg from 'imagemin-mozjpeg';
import imageminPngquant from 'imagemin-pngquant';
import imageminWebp from 'imagemin-webp';
(async () => {
const files = await imagemin(['src/images/*.{jpg,png}'], {
destination: 'dist/images',
plugins: [
imageminMozjpeg({ quality: 75 }),
imageminPngquant({ quality: [0.6, 0.8] }),
imageminWebp({ quality: 75 })
]
});
console.log(`压缩完成:${files.length} 张图片`);
})();
执行:
bash
node compress.js
目录大小 | 优化前 | 优化后 |
---|---|---|
50 MB | 50 MB | 12 MB |
4️⃣ 浏览器兼容 & 注意事项
场景 | 说明 |
---|---|
大图限制 | Canvas 最大 32767×32767,超界需分片 |
透明 PNG | 压缩为 JPEG 会丢失透明,保持 PNG 或转 WebP |
GIF | 使用 imagemin-gifsicle 压缩颜色数 |
移动端 | 统一使用 WebP + loading="lazy" |
5️⃣ 一键脚本(前端上传 + 压缩)
bash
git clone https://github.com/your-name/front-image-compress.git
cd front-image-compress
npm install
npm run dev
打开 http://localhost:3000
,拖拽图片即可实时压缩、预览、下载。
6️⃣ 总结一句话
前端图片压缩 = Canvas/Compressor 压缩 + WebP/Web Worker 优化 + 构建/部署链集成,按清单执行,体积直降 80%。