shop-front-end/doc/compressorjs-guide.md

319 lines
7.8 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# CompressorJS 实战使用文档
基于项目中的 `src/pages/approval/submit.vue` 实例编写。
## 1. 简介
CompressorJS 是一个轻量级的 JavaScript 图像压缩库,基于 Canvas API依赖少且易用。适用于文件上传前压缩可显著减少文件大小和上传时间。
## 2. 安装
```bash
pnpm add compressorjs
# 或
npm install compressorjs
```
## 3. 基础使用(基于项目实例)
### 3.1 基本语法
```javascript
import Compressor from 'compressorjs'
new Compressor(file, {
quality: 0.8,
maxWidth: 1280,
maxHeight: 1280,
success(result) {
// 压缩成功后的处理
},
error(err) {
// 压缩失败处理
}
})
```
### 3.2 实际项目代码解析
`submit.vue:54-115``handleFileUpload` 函数中:
```javascript
const handleFileUpload = async (items: UploaderFileListItem | UploaderFileListItem[]) => {
const files = Array.isArray(items) ? items : [items]
const uploadPromises = files.map(async (item) => {
const file = item.file as File
// 压缩文件
let compressedFile = file
try {
compressedFile = await new Promise<File>((resolve, reject) => {
new Compressor(file, {
quality: 0.8, // 压缩质量 0-1 之间
maxWidth: 1280, // 最大宽度
maxHeight: 1280, // 最大高度
success(result) {
// 转换为 File 对象,保持原始文件名
resolve(new File([result], file.name, {
type: 'image/jpeg', // 统一输出为 jpeg
lastModified: Date.now()
}))
},
error(err) {
reject(err)
}
})
})
} catch (error) {
console.error('压缩失败:', error)
// 压缩失败时使用原文件
}
// 继续上传...
})
}
```
**关键点:**
- 使用 Promise 包装 Compressor 的回调式 API
- 压缩失败时降级使用原文件
- 转换结果为标准 File 对象,便于后续处理
## 4. 配置参数详解
| 参数 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| `quality` | number | 0.8 | 压缩质量0-1 之间,值越小文件越小但质量越差 |
| `maxWidth` | number | Infinity | 最大宽度(像素) |
| `maxHeight` | number | Infinity | 最大高度(像素) |
| `minWidth` | number | 0 | 最小宽度 |
| `minHeight` | number | 0 | 最小高度 |
| `width` | number | - | 固定宽度(优先级高于 maxWidth |
| `height` | number | - | 固定高度(优先级高于 maxHeight |
| `resize` | string | 'cover' | 调整大小模式:'none'\|'contain'\|'cover'\|'crop' |
| `crop` | boolean | false | 是否裁剪(需配合 width/height |
| `rotate` | number | 0 | 旋转角度(度) |
| `blur` | number | 0 | 模糊半径 |
| `grayscale` | boolean | false | 转为灰度图 |
| `input` | string | 'file' | 输入类型 |
| `output` | string | 'blob' | 输出类型:'blob'\|'base64'\|'datauristring' |
## 5. 常见使用场景
### 5.1 批量图片压缩
```javascript
const compressFiles = async (files) => {
const promises = files.map(file => {
return new Promise((resolve, reject) => {
new Compressor(file, {
quality: 0.8,
maxWidth: 1280,
maxHeight: 1280,
success: resolve,
error: reject
})
})
})
return await Promise.all(promises)
}
```
### 5.2 限制文件大小
```javascript
const compressWithSizeLimit = (file, maxSizeMB = 2) => {
return new Promise((resolve, reject) => {
const maxSizeBytes = maxSizeMB * 1024 * 1024
new Compressor(file, {
quality: 0.6, // 降低质量确保文件更小
maxWidth: 1024,
maxHeight: 1024,
success: (result) => {
if (result.size > maxSizeBytes) {
// 仍超出限制,进一步压缩
new Compressor(file, {
quality: 0.4,
maxWidth: 800,
maxHeight: 800,
success: resolve,
error: reject
})
} else {
resolve(result)
}
},
error: reject
})
})
}
```
### 5.3 自定义输出格式
```javascript
// 输出为 base64
new Compressor(file, {
quality: 0.8,
maxWidth: 1280,
maxHeight: 1280,
output: 'datauristring',
success: (result) => {
const base64String = result // 已经是 base64 字符串
}
})
// 转换为 PNG
new Compressor(file, {
quality: 0.9,
maxWidth: 1280,
maxHeight: 1280,
success: (result) => {
new File([result], 'image.png', { type: 'image/png' })
}
})
```
## 6. 最佳实践
### 6.1 错误处理
```javascript
let compressedFile = originalFile
try {
compressedFile = await new Promise((resolve, reject) => {
new Compressor(file, options)
})
} catch (error) {
console.error('压缩失败:', error)
// 压缩失败时使用原文件,避免阻塞上传流程
}
```
### 6.2 文件类型检查
```javascript
const isImage = (file) => {
return /^image\//.test(file.type)
}
if (!isImage(file)) {
throw new Error('仅支持图片文件')
}
```
### 6.3 压缩级别建议
- **高质量**(适合产品图、头像):
```javascript
{
quality: 0.9,
maxWidth: 1920,
maxHeight: 1920
}
```
- **中等质量**(适合一般场景):
```javascript
{
quality: 0.8,
maxWidth: 1280,
maxHeight: 1280
}
```
- **高质量压缩**(适合缩略图、证明材料):
```javascript
{
quality: 0.6,
maxWidth: 800,
maxHeight: 800
}
```
### 6.4 进度提示(适用于 Vue/Vant
```javascript
item.status = 'uploading'
item.message = '压缩中...'
try {
// 压缩
item.message = '上传中...'
// 上传
item.status = 'done'
item.message = '上传成功'
} catch (error) {
item.status = 'failed'
item.message = '上传失败'
}
```
## 7. 性能优化
1. **避免重复压缩**:上传前检查文件是否已压缩
2. **合理设置尺寸**:根据业务需求设置最大宽高
3. **并发控制**:避免同时压缩过多文件
4. **使用 Web Workers**:大量文件时考虑使用 Web Worker
```javascript
// 并发控制示例
const processFilesWithLimit = async (files, limit = 3) => {
const results = []
const executing = []
for (const file of files) {
const promise = Promise.resolve().then(() => compressFile(file))
results.push(promise)
if (limit <= files.length) {
const executing_promise = promise.then(() =>
executing.splice(executing.indexOf(executing_promise), 1)
)
executing.push(executing_promise)
if (executing.length >= limit) {
await Promise.race(executing)
}
}
}
return Promise.all(results)
}
```
## 8. 注意事项
1. **只支持图片格式**CompressorJS 仅处理图片文件jpeg, png, gif 等)
2. **Canvas 依赖**:依赖浏览器 Canvas API部分旧浏览器可能不支持
3. **内存使用**:大文件压缩会消耗较多内存,建议控制文件大小
4. **EXIF 方向**:压缩可能会丢失图片 EXIF 方向信息
5. **文件类型转换**:默认输出 blob转换为 File 时需显式指定类型
## 9. 完整示例
参考项目中的完整实现:
- 文件:`src/pages/approval/submit.vue:54-115`
- 结合 Vant Uploader 组件的批量图片上传和压缩
- 集成错误处理和状态管理
- 支持压缩失败时的降级策略
## 10. 常见问题
**Q: 压缩后文件变大?**
A: 原文件已非常小,或开启了失真优化。尝试降低 quality 或设置更小的 maxWidth/maxHeight。
**Q: 支持 GIF 动态图?**
A: 不支持CompressorJS 仅处理静态图像。
**Q: 如何保持文件类型?**
A: 压缩时输出为 blob然后在 File 构造函数中指定目标类型:
```javascript
const type = file.type.includes('png') ? 'image/png' : 'image/jpeg'
new File([result], file.name, { type })
```