实现多张图片压缩及上传

需求

表单内容中包含图片(可能多张),采取方法是先请求多次将图片上传,将图片上传后返回的链接放到表单请求体中,再提交表单内容。

思路

使用Promise.all将图片全部上传之后再提交表单

const promises = imageList.value.map(it => uploadFile(it))
Promise.all(promises).then((res: any) => {
  postRequest.images = res.map((val: any) => {
    return import.meta.env.VITE_APP_BASE_URL val.data.url
  }).join(';')
  return postExposure(postRequest) //提交表单请求
}).then((res) => {
  if(res.status === 0) {
    Toast.success('发布成功!')
  }
}).catch((err) => {
  else Toast.fail('发布失败!')
})

经过了一番波折,解决了图片上传的问题后,考虑到图片大小,决定先上传再压缩。
经过一番比较,决定使用compressorjs这个库。(别问为啥不自己写,问就是折腾了好久没折腾出来)

compressorjs的基本使用

install
npm install compressorjs
基本使用
import Compress from 'compressorjs'
new Compressor(file, {
  quality: 0.6, //图片压缩比例,取值范围为0~1
  success(result) {
    const formData = new FormData();
    formData.append('file', result, result.name);
    //上传图片请求 示例,使用时替换成自己的上传请求即可
    axios.post('/post/upload', formData).then((res) => {
      console.log('上传成功');
    })
  },
  error(err) {
    console.log(err.message)
  }
})

通过之前自己写压缩图片方法过程中对图片压缩的一些了解,我知道这个压缩图片方法是异步的。这意味着我不能直接像下面这样将它放到我之前的代码中

const promises = imageList.value.map(it => {
  new Compressor(it.file, {
    quality: 0.6,
    success(result) {
      const formData = new FormData();
      formData.append('file', result, result.name);
      return uploadFile(formData)
    }
  })
}

这样的写法明显是错误的(然而第一次尝试的我并不知道,因此踩了一次坑)
由于此压缩过程是异步的,因此promises中全为undefined

经过了一番思索,最终我将代码改成了这样

/** 压缩图片 */
async function compressImage(file) {
  return new Promise((resolve, reject) => {
    new Compressor(file, {
      quality: 0.6,
      convertTypes: ['image/png', 'image/jpg'],
      convertSize: 1000000,
      success(result) {
        resolve(result)
      },
      error(err) {
        reject(err)
      }
    })
  })
}
/** 发布 */
function onPost() {
  const promises = imageList.value.map(async (val: any) => {
    if(val.file.size <= 1024*1024) {
      //小于1MB时不压缩直接上传
      return uploadFile(val)
    } else {
      const result = await compressImage(va file)
      const formData = new FormData()
      formData.append('file', result, resul name)
      return uploadFile(formData)
    }
  })
  Promise.all(promises).then((res: any) => {
    postRequest.images = res.map((val: any) => {
      return import.meta.env.VITE_APP_BASE_URL val.data.url
    }).join(';')
    return postExposure(postRequest)
  }).then((res) => {
    if(res.status === 0) {
      Toast.success('发布成功!')
    }
  }).catch((err) => {
    else Toast.fail('发布失败!')
  })
}

到此,总算是解决了压缩多张图片并上传的问题。
但是,其实这里还存在一些问题,比如没有处理图片上传失败的情况。需要根据情况改进~