|
|
|
|
@ -1,318 +0,0 @@
|
|
|
|
|
# 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 })
|
|
|
|
|
```
|