返回值参考
useDropup hook 返回的所有内容。
概览
const {
files, // 文件对象数组
state, // 当前状态
actions, // 可用操作
getDropProps, // 拖放区域的 props
getInputProps, // input 元素的 props
openFileDialog, // 打开文件选择器
} = useDropup();
files
表示所有已添加文件的 DropupFile 对象数组。
const { files } = useDropup();
files.forEach(file => {
console.log(file.id); // "abc123"
console.log(file.name); // "photo.jpg"
console.log(file.size); // 1234567
console.log(file.type); // "image/jpeg"
console.log(file.status); // "idle" | "uploading" | "complete" | "error"
console.log(file.progress); // 0-100
console.log(file.preview); // "blob:http://..." (仅图片)
console.log(file.uploadedUrl); // "https://..." (上传后)
console.log(file.error); // DropupError (如果失败)
});
DropupFile 属性
| 属性 | 类型 | 描述 |
|---|---|---|
id | string | 唯一标识符 |
file | File | 原始浏览器 File 对象 |
name | string | 文件名 |
size | number | 字节大小 |
type | string | MIME 类型 |
status | FileStatus | 当前状态 |
progress | number | 上传进度 (0-100) |
preview | string | undefined | 图片的预览 URL |
uploadedUrl | string | undefined | 上传成功后的 URL |
response | unknown | 服务器响应数据 |
error | DropupError | undefined | 上传失败时的错误 |
meta | Record<string, unknown> | 自定义元数据 |
FileStatus 值
| 状态 | 描述 |
|---|---|
'idle' | 文件已添加,未上传 |
'uploading' | 上传进行中 |
'complete' | 上传成功 |
'error' | 上传失败 |
'paused' | 上传已暂停 (可恢复上传) |
state
拖放区域的当前状态。
const { state } = useDropup();
console.log(state.isDragging); // 拖放时为 true
console.log(state.isDragAccept); // 拖放的文件有效时为 true
console.log(state.isDragReject); // 拖放的文件无效时为 true
console.log(state.isUploading); // 任何文件正在上传时为 true
console.log(state.progress); // 总体进度 0-100
console.log(state.status); // 'idle' | 'uploading' | 'complete' | 'error'
State 属性
| 属性 | 类型 | 描述 |
|---|---|---|
isDragging | boolean | 文件正在拖放区域上方 |
isDragAccept | boolean | 拖放的文件通过验证 |
isDragReject | boolean | 拖放的文件未通过验证 |
isUploading | boolean | 任何文件当前正在上传 |
progress | number | 所有文件的平均进度 (0-100) |
status | DropupStatus | 总体上传状态 |
DropupStatus 值
| 状态 | 描述 |
|---|---|
'idle' | 没有正在进行的上传 |
'uploading' | 一个或多个文件正在上传 |
'complete' | 所有上传成功完成 |
'error' | 一个或多个上传失败 |
actions
包含所有可用操作的对象。
const { actions } = useDropup();
// 开始上传
actions.upload(); // 上传所有空闲文件
actions.upload(['id1', 'id2']); // 上传特定文件
// 取消上传
actions.cancel(); // 取消所有上传
actions.cancel('file-id'); // 取消特定文件
// 移除文件
actions.remove('file-id'); // 移除特定文件
actions.reset(); // 移除所有文件
// 重试失败的上传
actions.retry(); // 重试所有失败的上传
actions.retry(['id1']); // 重试特定文件
// 以编程方式添加文件
actions.addFiles(fileList); // 添加 File[] 或 FileList
// 更新文件元数据
actions.updateFileMeta('file-id', { tag: 'important' });
Action 方法
upload(fileIds?)
开始上传文件。
// 上传所有空闲文件
actions.upload();
// 上传特定文件
actions.upload(['file-id-1', 'file-id-2']);
| 参数 | 类型 | 描述 |
|---|---|---|
fileIds | string[] (可选) | 要上传的特定文件 ID |
cancel(fileId?)
取消正在进行的上传。
// 取消所有上传
actions.cancel();
// 取消特定文件
actions.cancel('file-id');
| 参数 | 类型 | 描述 |
|---|---|---|
fileId | string (可选) | 要取消的特定文件 ID |
remove(fileId)
从列表中移除文件。
actions.remove('file-id');
| 参数 | 类型 | 描述 |
|---|---|---|
fileId | string | 要移除的文件 ID |
reset()
移除所有文件并重置状态。
actions.reset();
retry(fileIds?)
重试失败的上传。
// 重试所有失败的上传
actions.retry();
// 重试特定文件
actions.retry(['file-id-1']);
| 参数 | 类型 | 描述 |
|---|---|---|
fileIds | string[] (可选) | 要重试的特定文件 ID |
addFiles(files)
以编程方式添加文件。
// 从剪贴板
document.addEventListener('paste', (e) => {
const files = e.clipboardData?.files;
if (files) {
actions.addFiles(files);
}
});
// 从其他来源
actions.addFiles([file1, file2]);
| 参数 | 类型 | 描述 |
|---|---|---|
files | File[] | FileList | 要添加的文件 |
updateFileMeta(fileId, meta)
更新文件元数据。
actions.updateFileMeta('file-id', {
description: '我的照片',
tags: ['假期', '2024'],
});
| 参数 | 类型 | 描述 |
|---|---|---|
fileId | string | 要更新的文件 ID |
meta | Record<string, unknown> | 要合并的元数据 |
getDropProps
返回要展开到拖放区域元素上的 props。
const { getDropProps, getInputProps } = useDropup();
<div {...getDropProps()}>
<input {...getInputProps()} />
将文件拖放到这里
</div>
使用自定义 Props
<div
{...getDropProps({
className: 'my-dropzone',
onClick: (e) => {
// 您的自定义点击处理器
console.log('已点击!');
},
})}
>
<input {...getInputProps()} />
</div>
返回的 Props
| 属性 | 类型 | 描述 |
|---|---|---|
onDragEnter | function | 拖放进入处理器 |
onDragOver | function | 拖放悬停处理器 |
onDragLeave | function | 拖放离开处理器 |
onDrop | function | 拖放处理器 |
onClick | function | 点击处理器 (打开对话框) |
role | string | 无障碍角色 |
tabIndex | number | 焦点的 tab 索引 |
getInputProps
返回要展开到隐藏文件输入上的 props。
const { getInputProps } = useDropup();
<input {...getInputProps()} />
使用自定义 Props
<input
{...getInputProps({
id: 'file-input',
name: 'files',
})}
/>
返回的 Props
| 属性 | 类型 | 描述 |
|---|---|---|
type | 'file' | Input 类型 |
accept | string | 接受的文件类型 |
multiple | boolean | 允许多个文件 |
onChange | function | 更改处理器 |
style | object | 隐藏样式 |
openFileDialog
以编程方式打开文件选择器的函数。
const { openFileDialog } = useDropup();
<button onClick={openFileDialog}>
浏览文件
</button>
使用示例
完整文件列表
function FileList() {
const { files, actions, state } = useDropup({
upload: { url: '/api/upload' },
});
return (
<div>
<h3>文件 ({files.length})</h3>
{files.map(file => (
<div key={file.id}>
{file.preview && (
<img src={file.preview} alt="" width={50} />
)}
<span>{file.name}</span>
<span>{(file.size / 1024).toFixed(1)} KB</span>
<span>{file.status}</span>
{file.status === 'uploading' && (
<progress value={file.progress} max={100} />
)}
{file.status === 'error' && (
<>
<span style={{ color: 'red' }}>{file.error?.message}</span>
<button onClick={() => actions.retry([file.id])}>重试</button>
</>
)}
<button onClick={() => actions.remove(file.id)}>移除</button>
</div>
))}
{state.isUploading && (
<p>上传中... {state.progress}%</p>
)}
<button
onClick={() => actions.upload()}
disabled={state.isUploading || files.length === 0}
>
全部上传
</button>
<button onClick={() => actions.reset()}>
清除所有
</button>
</div>
);
}
拖放状态样式
function StyledDropzone() {
const { state, getDropProps, getInputProps } = useDropup({
accept: 'image/*',
});
const getStyle = () => {
if (state.isDragAccept) return { borderColor: 'green', backgroundColor: '#e8f5e9' };
if (state.isDragReject) return { borderColor: 'red', backgroundColor: '#ffebee' };
if (state.isDragging) return { borderColor: 'blue', backgroundColor: '#e3f2fd' };
return { borderColor: 'gray', backgroundColor: 'white' };
};
return (
<div
{...getDropProps()}
style={{
border: '2px dashed',
borderRadius: 8,
padding: 40,
textAlign: 'center',
transition: 'all 0.2s',
...getStyle(),
}}
>
<input {...getInputProps()} />
{state.isDragReject ? (
<p>仅接受图片!</p>
) : (
<p>将图片拖放到这里</p>
)}
</div>
);
}