跳转到主要内容

返回值参考

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 属性

属性类型描述
idstring唯一标识符
fileFile原始浏览器 File 对象
namestring文件名
sizenumber字节大小
typestringMIME 类型
statusFileStatus当前状态
progressnumber上传进度 (0-100)
previewstring | undefined图片的预览 URL
uploadedUrlstring | undefined上传成功后的 URL
responseunknown服务器响应数据
errorDropupError | undefined上传失败时的错误
metaRecord<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 属性

属性类型描述
isDraggingboolean文件正在拖放区域上方
isDragAcceptboolean拖放的文件通过验证
isDragRejectboolean拖放的文件未通过验证
isUploadingboolean任何文件当前正在上传
progressnumber所有文件的平均进度 (0-100)
statusDropupStatus总体上传状态

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']);
参数类型描述
fileIdsstring[] (可选)要上传的特定文件 ID

cancel(fileId?)

取消正在进行的上传。

// 取消所有上传
actions.cancel();

// 取消特定文件
actions.cancel('file-id');
参数类型描述
fileIdstring (可选)要取消的特定文件 ID

remove(fileId)

从列表中移除文件。

actions.remove('file-id');
参数类型描述
fileIdstring要移除的文件 ID

reset()

移除所有文件并重置状态。

actions.reset();

retry(fileIds?)

重试失败的上传。

// 重试所有失败的上传
actions.retry();

// 重试特定文件
actions.retry(['file-id-1']);
参数类型描述
fileIdsstring[] (可选)要重试的特定文件 ID

addFiles(files)

以编程方式添加文件。

// 从剪贴板
document.addEventListener('paste', (e) => {
const files = e.clipboardData?.files;
if (files) {
actions.addFiles(files);
}
});

// 从其他来源
actions.addFiles([file1, file2]);
参数类型描述
filesFile[] | FileList要添加的文件

updateFileMeta(fileId, meta)

更新文件元数据。

actions.updateFileMeta('file-id', {
description: '我的照片',
tags: ['假期', '2024'],
});
参数类型描述
fileIdstring要更新的文件 ID
metaRecord<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

属性类型描述
onDragEnterfunction拖放进入处理器
onDragOverfunction拖放悬停处理器
onDragLeavefunction拖放离开处理器
onDropfunction拖放处理器
onClickfunction点击处理器 (打开对话框)
rolestring无障碍角色
tabIndexnumber焦点的 tab 索引

getInputProps

返回要展开到隐藏文件输入上的 props。

const { getInputProps } = useDropup();

<input {...getInputProps()} />

使用自定义 Props

<input
{...getInputProps({
id: 'file-input',
name: 'files',
})}
/>

返回的 Props

属性类型描述
type'file'Input 类型
acceptstring接受的文件类型
multipleboolean允许多个文件
onChangefunction更改处理器
styleobject隐藏样式

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>
);
}