📈前端图片压缩实战:体积直降 80%,LCP 提升 2 倍

本文提供 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%。

相关推荐
非凡ghost34 分钟前
MPC-BE视频播放器(强大视频播放器) 中文绿色版
前端·windows·音视频·软件需求
Stanford_110643 分钟前
React前端框架有哪些?
前端·微信小程序·前端框架·微信公众平台·twitter·微信开放平台
洛可可白1 小时前
把 Vue2 项目“黑盒”嵌进 Vue3:qiankun 微前端实战笔记
前端·vue.js·笔记
学习同学2 小时前
从0到1制作一个go语言游戏服务器(二)web服务搭建
服务器·前端·golang
-D调定义之崽崽2 小时前
【初学】调试 MCP Server
前端·mcp
四月_h2 小时前
vue2动态实现多Y轴echarts图表,及节点点击事件
前端·javascript·vue.js·echarts
文心快码BaiduComate2 小时前
用Zulu轻松搭建国庆旅行4行诗网站
前端·javascript·后端
正义的大古3 小时前
OpenLayers地图交互 -- 章节十八:拖拽旋转和缩放交互详解
javascript·vue.js·openlayers
行者..................4 小时前
手动编译 OpenCV 4.1.0 源码,生成 ARM64 动态库 (.so),然后在 Petalinux 中打包使用。
前端·webpack·node.js
聪明的笨猪猪4 小时前
Java SE “JDK1.8新特性”面试清单(含超通俗生活案例与深度理解)
java·经验分享·笔记·面试