前端图片优化展示

1.预加载图片

通过JavaScript动态创建Image对象:通过new Image()预加载图片数组,适用于需要精确控制加载时机的场景

2.懒加载图片

懒加载通过延迟非可视区域图片的请求来优化首屏性能。主流实现方案有

  • 原生属性‌:HTML5的loading="lazy"属性,简单但存在兼容性问题
  • Intersection Observer API‌:现代浏览器推荐方案,通过观察元素与视窗交叉状态触发加载,性能优于传统滚动事件。
  • 传统滚动监听‌:计算元素offsetTop与视窗位置关系,需配合节流函数优化性能。

3.压缩图片

  • Commpressor.js (推荐)

Compressor.js通过Canvas原生实现像素级压缩,在保持90%视觉质量的同时,实现平均65-85%的压缩率。兼容下现代浏览器(包括移动端),支持主流图片格式(JPEG/PNG/WEBP)。

参考:字节跳动图像压缩方案

导入依赖

npm install compressorjs
或者
yarn add compressorjs

或者直接引入cdn的压缩js。

<script src="https://cdn.jsdelivr.net/npm/compressorjs@1.2.1/dist/compressor.min.js"></script>

基础使用

// 获取文件对象(例如通过input[type=file])
const file = document.querySelector('input[type=file]').files[0];

// 初始化压缩器
new Compressor(file, {
quality: 0.8, // 压缩质量(0-1)
maxWidth: 1920, // 最大宽度
maxHeight: 1080, // 最大高度
  success(result) {
    // 压缩成功回调
    const formData = new FormData();
    formData.append('file', result, result.name);
    
    // 上传到服务器示例
    fetch('/api/upload', {
      method: 'POST',
      body: formData,
    });
  },
  error(err) {
    console.error('压缩失败:', err);
  },
});

进阶配值

new Compressor(file, {
// 压缩质量配置
quality: 0.6,

// 尺寸限制
width: 800,      // 固定宽度
height: 600,     // 固定高度
resize: 'cover', // 缩放模式(cover/contain等)

// 格式转换
convertSize: 102400, // 超过100KB自动转成JPEG
mimeType: 'auto',    // 自动检测最佳格式

// 高级处理
strict: true,      // 严格模式(精确尺寸)
orient: true,      // 保持EXIF方向信息
checkOrientation: true, // 检查EXIF方向

// 钩子函数
  beforeDraw(ctx, canvas) {
    // 压缩前可对Canvas进行额外处理
    ctx.filter = 'grayscale(100%)';
  },

  drew(ctx, canvas) {
    // 压缩后可进行后处理
    const watermark = document.createElement('img');
    watermark.onload = () => {
      ctx.drawImage(watermark, 10, 10, 100, 50);
    };
    watermark.src = '/watermark.png';
  },
});

完整代码

<!DOCTYPE html>
<input type="file" accept="image/*" id="uploader">
<div id="preview"></div>

<script src="https://cdn.jsdelivr.net/npm/compressorjs@1.2.1/dist/compressor.min.js"></script>
<script>
document.getElementById('uploader').addEventListener('change', (e) => {
  const file = e.target.files[0];
  if (!file) return;

  new Compressor(file, {
    quality: 0.7,
    maxWidth: 1024,
    convertSize: 500000, // 超过500KB转成WEBP
    success(result) {
      // 显示压缩前后对比
      const preview = document.getElementById('preview');
      
      // 原始文件预览
      const origin = new Image();
      origin.src = URL.createObjectURL(file);
      origin.style = 'width: 300px; border: 2px solid red;';
      
      // 压缩后预览
      const compressed = new Image();
      compressed.src = URL.createObjectURL(result);
      compressed.style = 'width: 300px; border: 2px solid green;';
      
      // 显示文件信息
      const info = document.createElement('div');
      info.innerHTML = `
        原始大小:${(file.size/1024).toFixed(2)}KB
        压缩后:${(result.size/1024).toFixed(2)}KB
        压缩率:${(100 - (result.size/file.size*100)).toFixed(1)}%
      `;
      
      preview.append(origin, compressed, info);
    },
    error(err) {
      alert(`压缩失败: ${err.message}`);
    }
  });
});
</script>

注意事项

  • 格式转换限制:Safari 14以下不支持WEBP格式

  • 质量设置建议:

    • JPEG推荐0.6-0.8

    • PNG推荐保持1.0(无损)

  • 性能优化:大文件(>5MB)建议先分片读取

  • 兼容性处理:对于旧版浏览器需要polyfill:

// 添加Promise polyfill
if (typeof Promise === 'undefined') {
  script.async = false;
  document.write('<script src="https://cdn.jsdelivr.net/npm/es6-promise@4.2.8/dist/es6-promise.auto.min.js"><\/script>');
}
<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>

  • 原生 Canvas 压缩(零依赖)

<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>
/**
 * 将 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);
  });
}

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值