文件处理
Dropup 为处理文件提供无缝体验,从选择文件到上传完成。
文件选择方法
拖放
使用 getDropProps() 在任何元素上启用拖放:
function DropZone() {
const { getDropProps, getInputProps, state } = useDropup();
return (
<div
{...getDropProps()}
style={{
border: state.isDragging ? '2px dashed blue' : '2px dashed gray',
backgroundColor: state.isDragging ? '#f0f8ff' : 'transparent',
}}
>
<input {...getInputProps()} />
<p>将文件拖放到此处</p>
</div>
);
}
点击选择
默认情况下,拖放区域也可点击:
<div {...getDropProps()}>
<input {...getInputProps()} />
<p>点击或将文件拖放到此处</p>
</div>
编程式选择
以编程方式打开文件对话框:
const { openFileDialog } = useDropup();
<button onClick={openFileDialog}>
选择文件
</button>
编程式添加文件
直接添加文件(适用于粘贴事件或集成):
const { actions } = useDropup();
// 从剪贴板
document.addEventListener('paste', (e) => {
const files = e.clipboardData?.files;
if (files?.length) {
actions.addFiles(files);
}
});
文件对象结构
files 数组中的每个文件都具有以下结构:
interface DropupFile {
// 标识
id: string; // 唯一标识符(自动生成)
file: File; // 原始浏览器 File 对象
// 元数据
name: string; // 文件名
size: number; // 大小(字节)
type: string; // MIME 类型(例如 "image/png")
// 预览(用于图片)
preview?: string; // 用于预览的对象 URL
// 上传状态
status: FileStatus; // 'idle' | 'uploading' | 'complete' | 'error' | 'paused'
progress: number; // 0-100
// 结果
uploadedUrl?: string; // 上传成功后的 URL
response?: unknown; // 服务器响应
error?: DropupError; // 失败时的错误详情
// 自定义数据
meta?: Record<string, unknown>;
}
文件状态生命周期
idle → uploading → complete
↘ error → (retry) → uploading
↘ paused → (resume) → uploading
状态值
| 状态 | 描述 |
|---|---|
idle | 文件已添加但尚未上传 |
uploading | 正在上传 |
complete | 上传成功 |
error | 上传失败 |
paused | 上传已暂停(用于可恢复上传) |
处理文件
访问文件
const { files } = useDropup();
// 所有文件
console.log(files);
// 按状态过滤
const uploading = files.filter(f => f.status === 'uploading');
const completed = files.filter(f => f.status === 'complete');
const failed = files.filter(f => f.status === 'error');
删除文件
const { files, actions } = useDropup();
// 删除单个文件
actions.remove(files[0].id);
// 删除所有文件
actions.reset();
更新文件元数据
const { actions } = useDropup();
// 添加自定义元数据
actions.updateFileMeta(fileId, {
customField: 'value',
category: 'documents',
});
文件预览
对于图片文件,Dropup 可以生成预览 URL:
const { files } = useDropup({
generatePreviews: true, // 默认:true
});
// 在 UI 中使用预览
{files.map(file => (
file.preview && (
<img
src={file.preview}
alt={file.name}
style={{ maxWidth: 100, maxHeight: 100 }}
/>
)
))}
内存管理
预览 URL 是消耗内存的对象 URL。Dropup 会在文件被删除或组件卸载时自动撤销它们。
文件大小格式化
显示文件大小的辅助函数:
function formatFileSize(bytes: number): string {
if (bytes === 0) return '0 Bytes';
const k = 1024;
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
}
// 使用方法
{files.map(file => (
<span>{formatFileSize(file.size)}</span>
))}
处理大文件
对于大文件,考虑使用分块上传:
import { useDropup, createChunkedUploader } from '@samithahansaka/dropup';
const { files } = useDropup({
upload: createChunkedUploader({
url: '/api/upload',
chunkSize: 5 * 1024 * 1024, // 5MB 分块
}),
});
有关更多详细信息,请参阅分块上传。