vue3+element-plus图片上传,前端压缩(纯函数,无插件)

方法:直接复制

javascript 复制代码
// 核心压缩方法(纯函数,无this)
// ✅ 优化后的【可用】压缩方法(替换你原有代码里的同名方法)
const imageCompress = async (file, quality = 0.7, maxWidth = 1920) => {
  return new Promise((resolve, reject) => {
    if (!file || !file.type.startsWith('image/')) {
      reject(new Error('非图片文件,无需压缩'));
      return;
    }
    const img = new Image()
    img.setAttribute('crossOrigin', 'anonymous')
    const originalUrl = URL.createObjectURL(file)
    img.src = originalUrl

    // 图片加载失败容错
    img.onerror = () => {
      URL.revokeObjectURL(originalUrl);
      reject(new Error('图片加载失败,无法压缩'));
    };

    img.onload = () => {
      let { width, height } = img
      // 等比例缩放,避免变形
      if (width > maxWidth) {
        const scale = maxWidth / width
        width = maxWidth
        height = height * scale
      }

      const canvas = document.createElement('canvas')
      const ctx = canvas.getContext('2d')
      canvas.width = width
      canvas.height = height
      ctx.clearRect(0, 0, width, height)
      ctx.drawImage(img, 0, 0, width, height)

      canvas.toBlob(
        (blob) => {
          if (!blob) {
            reject(new Error('图片压缩失败'));
            return;
          }
          // 生成压缩后的File文件,保留原文件名/格式
          const compressFile = new File([blob], file.name, { type: file.type })
          const compressUrl = URL.createObjectURL(blob)
          resolve({
            originalUrl,
            compressUrl,
            originalSize: file.size,
            compressSize: blob.size,
            compressFile // ✅ 核心:压缩后的文件对象,用于后续上传
          })
        },
        file.type,
        quality // 0.7是9M图片的黄金值:体积压至800KB左右,画质无明显损失
      )
      URL.revokeObjectURL(originalUrl)
    }
  })
}

调用:图片上传的beforeUpload方法中使用

javascript 复制代码
const beforeUpload = async (file) => {
  // 1. 原有格式校验:保留不变
  const isImage = ['image/jpeg', 'image/png'].includes(file.type)
  const isLt10M = file.size / 1024 / 1024 <= 10

  if (!isImage) {
    ElMessage.error('只能上传JPG/PNG格式图片!')
    return false // 校验失败,终止上传
  }
  if (!isLt10M) {
    ElMessage.error('图片大小不能超过10M!')
    return false // 校验失败,终止上传
  }

  // 2. 校验通过 → 执行图片压缩(核心新增逻辑)
  try {
    console.log(`开始压缩【${file.name}】,原大小:${(file.size/1024/1024).toFixed(2)}MB`)
    const compressRes = await imageCompress(file, 0.7, 1920)
    console.log(`压缩完成,新大小:${(compressRes.compressSize/1024/1024).toFixed(2)}MB`)
    ElMessage.success(`图片压缩成功,体积减小${Math.round((1 - compressRes.compressSize/file.size)*100)}%`)
    
    // ✅ 返回压缩后的文件 → el-upload会自动用这个文件继续上传流程
    return compressRes.compressFile
  } catch (err) {
    ElMessage.error(`图片压缩失败:${err.message},将上传原图`)
    return file // 压缩失败兜底,上传原图
  }
}

实测:8M左右压缩到300k-500k左右,具体大小可以自己按压缩比例调整

相关推荐
gs801403 小时前
解构 Cordis:面向“时空可组合性”的 TypeScript 元框架深度剖析
前端·javascript·typescript
Highcharts.js3 小时前
Highcharts大数据渲染模块Boost实战与参数最佳实践表
javascript·数据可视化·boost·highcharts·大数据渲染·加速配置·参数表
岁岁种桃花儿3 小时前
Vue核心语法第一篇:Vue是什么?
前端·javascript·vue.js
Highcharts.js4 小时前
数据可视化避坑指南 ——开发中常见图表错误与修复方案
javascript·信息可视化·数据可视化·highcharts·数据可视化避坑·修复方案
观无4 小时前
若依EasyExcel实现单元格合并
开发语言·前端·javascript
愚公搬代码4 小时前
【愚公系列】《Web应用安全》001-VMware的安装
前端·安全
xiaohaiAIgeo4 小时前
【2026年】HG/T 20656-2024化工暖通空调设计规范:新版标准的变化与影响
java·前端·javascript·科普知识
立少→万能汉编5 小时前
用“立少→超文本”写静态网页,标签<倍>
服务器·前端·javascript
weixin_431600445 小时前
NestJS 入门(7):生命周期钩子——构造函数和 `OnModuleInit` 差在哪?
前端·后端·学习·node.js·nest.js
你挚爱的强哥5 小时前
【chromeDownload】自定义组件:多用于登录框底部提供下载Chrome谷歌浏览器的链接
前端·vue.js·chrome