前端使用Compressor.js实现图片压缩上传
Compressor.js官方文档
安装
| 1
 | npm install compressorjs
 | 
使用
在使用ElementUI或者其他UI框架的上传组件时,都会有上传之前的钩子函数,在这个函数中可以拿到原始file,这里我用VantUI的上传做演示
| 12
 3
 4
 5
 6
 7
 
 | <van-uploader:max-count="prop.limit"
 v-model="state.fileList"
 :after-read="afterRead"
 :before-read="beforeRead"
 @delete="deleteFile"
 />
 
 | 
afterRead函数时上传之前的钩子,可以获取到file
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 
 | <template><div>
 <van-uploader
 :max-count="prop.limit"
 v-model="state.fileList"
 :after-read="afterRead"
 :before-read="beforeRead"
 @delete="deleteFile"
 />
 </div>
 </template>
 <script setup>
 import { reactive, defineEmits, defineProps, watch } from 'vue'
 import { FileUploadFun } from '@/api/index.js'
 import { useCustomFieldValue } from '@vant/use'
 import { Toast } from 'vant'
 import Compressor from 'compressorjs'
 
 const prop = defineProps({
 url: {
 type: String,
 default: '',
 },
 limit: {
 type: Number,
 default: 5,
 },
 })
 const emit = defineEmits(['onSuccess'])
 const state = reactive({
 fileList: [],
 })
 
 watch(
 () => prop.url,
 () => {
 if (prop.url) {
 state.fileList = []
 prop.url.split(',').forEach((item) => {
 state.fileList.push({
 url: item,
 })
 })
 }
 }
 )
 
 
 const beforeRead = (file) => {
 return new Promise((resolve, reject) => {
 new Compressor(file, {
 
 quality: 0.2,
 success(result) {
 
 let newFile = new File([result], file.name, { type: file.type })
 resolve(newFile)
 },
 error(err) {
 reject(err)
 },
 })
 })
 }
 
 
 const afterRead = (file) => {
 file.status = 'uploading'
 file.message = '上传中...'
 
 FileUploadFun(file.file)
 .then((res) => {
 file.status = 'done'
 file.message = '上传成功'
 let urls = state.fileList.map((i) => i.url)
 urls.pop()
 urls.push(res.data.url)
 
 emit('onSuccess', urls.join(','))
 })
 .catch(() => {
 state.fileList.pop()
 file.status = 'done'
 Toast('上传失败')
 })
 }
 
 
 const deleteFile = () => {
 emit('onSuccess', state.fileList.map((i) => i.url).join(','))
 }
 
 
 useCustomFieldValue(() => state.fileList.map((item) => item.url).join(','))
 </script>
 
 | 
示例
| Quality | 原始大小 | 压缩后大小 | 压缩比 | Description | 
| 0 | 2.12 MB | 114.61 KB | 94.72% | - | 
| 0.2 | 2.12 MB | 349.57 KB | 83.90% | - | 
| 0.4 | 2.12 MB | 517.10 KB | 76.18% | - | 
| 0.6 | 2.12 MB | 694.99 KB | 67.99% | 推荐 | 
| 0.8 | 2.12 MB | 1.14 MB | 46.41% | 推荐 | 
| 1 | 2.12 MB | 2.12 MB | 0% | 不推荐 | 
| NaN | 2.12 MB | 2.01 MB | 5.02% | - | 
测试效果

可以看到压缩前的图片大小3.29M,压缩后342KB
下面是前后的图片对比
原图

压缩后的图
