场景:
web上传一组照片,供移动端展示(反过来也是)。图片太大时,对图片展示很不友好。比如web端上传一组3×3MB的照片,在小程序端展示时就要展示9MB大小的图像。流量消耗大,切网速慢的时候白屏时间会比较长,影响用户体验。所以最好对图片进行压缩处理。
解决方案:
- 上传图片时前端先进行图片压缩,压缩后传给Server或上传CDN,移动端直接拿到图片不处理就可以展示。
- 上传图片时前端不处理直接传给Server,由Server处理,移动端展示。
- 上传图片时前端和Server都不处理,移动端展示的时候先对图片预处理再展示。
大部分情况推荐第一种。优点:上传节省时间、节省服务器存储空间、减少网络负担
前端图片鸭嗦
使用插件:js-image-compressor,一个js库,可以在客户端(浏览器)压缩图片,可以在上传时减少带宽,节约空间,提高首屏加载预览体验。
一、实现原理(略,后续补充)
二、安装:
npm/pnpm install js-image-compressor
三、应用:
创建一个 compressImg.ts文件。
import ImageCompressor from 'js-image-compressor'
/**
* 图片压缩
* @notes 这里使用的api函数可以在MDN文档查到具体使用方式。
* @description
* 1.该函数用于图片压缩。接收一个File对象和一个最大大小(默认400KB)。
* 2.如果文件大小小于等于目标大小,则不压缩,直接转换为Base64。
* 3.若超过maxSize,则使用ImageCompressor库压缩图片至指定质量、最大宽度和高度,然后将结果转换为Base64。
* 4.返回一个包含base64字符串和File对象的Promise。
* @param file 待压缩的图片文件
* @param maxSize 文件大小,最大值默认400kb
* @returns
*/
export const compressImg = async (file: File, maxSize = 400): Promise<{ baseStr: string; file: File }> => {
const convertToBase64 = (blob: Blob): Promise<string | ArrayBuffer | null> =>
new Promise((resolve, reject) => {
// 读取blob/file对象
const reader = new FileReader()
reader.readAsDataURL(blob)
reader.onloadend = () => resolve(reader.result)
reader.onerror = (error) => reject(error)
})
// 字节数
const targetSize = maxSize * 1024
if (file.size <= targetSize) {
const base64Data = await convertToBase64(file)
const baseStr = typeof base64Data === 'string' ? base64Data : ''
return { baseStr, file: file }
}
return new Promise<{ baseStr: string; file: File }>((resolve, reject) => {
new ImageCompressor({
file,
quality: 0.4,
maxWidth: 4640,
maxHeight: 4640,
success(result: File) {
// 这里的result是已经压缩过后的文件,可以打印对比一下与源文件的大小差异
// console.log(result)
convertToBase64(result)
.then((base64Data) => {
const baseStr = typeof base64Data === 'string' ? base64Data : ''
resolve({ baseStr, file: result })
})
.catch((error) => {
reject(error)
})
},
error(err: Error) {
reject(err)
}
})
})
}
在其他需要的地方引入(Vue3 + typescript项目)
// 导入
import { compressImg } from '@/libs/utils/compressImg'
// code ...
// code ...
const uploadImage = async (file: File) => {
let compressData: { baseStr: string; file: File } = await compressImg(file)
// 上传逻辑
// code ...
}