导读:本期聚焦于小伙伴创作的《JS如何实现图片压缩上传?3步完成客户端图片压缩与上传》,敬请观看详情。直接把手机拍的几兆照片塞进表单上传,往往会把服务器带宽和存储撑爆,用户也得干等进度条。其实浏览器自带Canvas和File API,能在本地把图片缩到合适尺寸再发请求。核心做法是先通过input拿到File对象,用URL.createObjectURL转成可绘制的图像源,接着在canvas上按目标宽高压缩并重绘,最后用toBlob导出新文件走FormData上传。这种方式不依赖任何后端处理,上传体积能降到原来的十分之一,且兼容现代浏览器。需要注意的是iOS设备上canvas尺寸过大可能崩溃,应限制最长边并适当降质。

在Web开发中,用户从手机或相机选择的原始图片常常达到数兆字节,直接上传既浪费流量又加重服务器负担。借助JavaScript的File API与Canvas,我们可以完全在浏览器端完成图片压缩,再使用FormData提交到服务器。下面通过一个完整示例,分三个步骤说明具体实现方式。

JS如何实现图片压缩上传?3步完成客户端图片压缩与上传

第一步:获取用户选择的图片文件

我们使用一个隐藏或可见的<input type="file">元素,监听其change事件,从中拿到用户选择的File对象。File对象继承了Blob,包含了图片的原始二进制数据和类型信息。此时图片还没有被读取到内存中绘制,仅仅是得到了引用。

为了限制用户误操作,可以通过accept属性约束只能选图片,并通过multiple属性决定是否允许多张。拿到File后,我们不能直接把它画到Canvas上,而是要先生成一个临时的URL,或者改用FileReader读取为DataURL。实际项目中更推荐URL.createObjectURL,因为它不会把整个文件以 base64 形式塞进内存,性能更好。

<input type="file" id="fileInput" accept="image/*" />
<script>
  const input = document.getElementById('fileInput');
  input.addEventListener('change', (e) => {
    const file = e.target.files[0];
    if (!file) return;
    console.log('原始大小', file.size, '类型', file.type);
    // 下一步将用这个file进行压缩
  });
</script>

第二步:使用Canvas进行图片压缩

将File对象转换为HTMLImageElement后,我们可以把图像绘制到指定尺寸的Canvas上。压缩的本质是:把大图按目标宽度等比缩放,绘制到较小的画布区域,再调用canvas.toBlob方法以指定图片格式和清晰度导出。通常JPEG格式配合0.7左右的quality参数,能在肉眼难以察觉的情况下大幅减小体积。

需要注意,iOS Safari对Canvas最大尺寸有限制,单边超过约4096像素就可能绘制失败。因此代码里应计算缩放比例,保证最长边不超过设定值。下面函数接收File和最大边长,返回压缩后的Blob,整个过程都是异步的,方便用await串联后续上传。

function compressImage(file, maxSide = 1000, quality = 0.7) {
  return new Promise((resolve, reject) => {
    const url = URL.createObjectURL(file);
    const img = new Image();
    img.onload = () => {
      URL.revokeObjectURL(url);
      let { width, height } = img;
      if (width > height && width > maxSide) {
        height = Math.round(height * maxSide / width);
        width = maxSide;
      } else if (height > maxSide) {
        width = Math.round(width * maxSide / height);
        height = maxSide;
      }
      const canvas = document.createElement('canvas');
      canvas.width = width;
      canvas.height = height;
      const ctx = canvas.getContext('2d');
      ctx.drawImage(img, 0, 0, width, height);
      canvas.toBlob(
        (blob) => resolve(blob),
        'image/jpeg',
        quality
      );
    };
    img.onerror = reject;
    img.src = url;
  });
}

第三步:通过FormData上传压缩后的图片

得到压缩Blob后,我们把它包装成新的File或直接作为Blob放进FormData。使用fetch或XMLHttpRequest发送到后端接口即可。由于Blob本身没有文件名,若服务端依赖filename字段,可以手动构造new File([blob], 'compressed.jpg', { type: 'image/jpeg' })。

相比直接传原图,压缩后体积通常只有原先的10%到30%,上传耗时显著下降。下面的示例演示了如何衔接前两步,并把结果提交到ipipp.com示例接口。注意实际项目中应加上错误处理与上传进度提示,提升体验。

async function handleUpload(file) {
  try {
    const compressedBlob = await compressImage(file, 1200, 0.75);
    const formData = new FormData();
    formData.append('image', compressedBlob, 'compressed.jpg');
    const resp = await fetch('https://ipipp.com/api/upload', {
      method: 'POST',
      body: formData
    });
    if (!resp.ok) throw new Error('上传失败');
    const data = await resp.json();
    console.log('服务器返回', data);
  } catch (err) {
    console.error('处理过程出错', err);
  }
}

常见问题与优化建议

第一,PNG图片含透明通道,用image/jpeg导出会丢失透明度并填充黑色背景。若业务必须保留透明,应判断原图类型,对PNG仅做尺寸缩放而不强转格式,或使用image/webp(需注意兼容性)。第二,批量上传时要避免同时创建多个超大Canvas,可改为队列串行压缩,防止移动端内存溢出。

第三,压缩参数应根据场景调整:头像类可更激进(质量0.6、边长400),摄影分享类则需保留细节(质量0.85、边长1600)。通过合理封装上述三步逻辑,就能在任意现代浏览器中稳定实现客户端图片压缩与上传,减轻服务端压力并改善用户等待时间。

JavaScript图片压缩File_API修改时间:2026-08-07 04:54:24

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。