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左右,具体大小可以自己按压缩比例调整

相关推荐
SuperEugene4 分钟前
Axios + Vue 错误处理规范:中后台项目实战,统一捕获系统 / 业务 / 接口异常|API 与异步请求规范篇
前端·javascript·vue.js·前端框架·axios
行走的陀螺仪5 分钟前
手写 Vue3 极简 i18n
前端·javascript·vue.js·国际化·i18n
羽沢3113 分钟前
一篇简单的STOMP教程QAQ
前端·javascript·stomp
code_Bo14 分钟前
使用AI完成Swagger接口类型在前端自动生成的工具
前端·后端·架构
加个鸡腿儿37 分钟前
从"包裹器"到"确认按钮"——一个组件的三次重构
前端·vue.js·设计模式
Kel39 分钟前
深入 OpenAI Node SDK:一个请求的奇幻漂流
javascript·人工智能·架构
子兮曰42 分钟前
AI写代码坑了90%程序员!这5个致命bug,上线就炸(附避坑清单)
前端·javascript·后端
猪八宅百炼成仙1 小时前
PanelSplitter 组件:前端左右布局宽度调整的实用解决方案
前端
BUG胡汉三1 小时前
自建在线文档编辑服务:基于 Collabora CODE + Spring Boot + Vue 3 的完整实现
vue.js·spring boot·后端·在线编辑
锋利的绵羊1 小时前
【解决方案】微信浏览器跳出到浏览器打开、跳转到app,安卓&ios
前端