用react 函数式组件 写一个大文件上传,实现断点续传,秒传,分片上传,上传过的分片不再上传
时间: 2024-02-08 07:11:30 浏览: 32
好的,下面是一个使用React函数式组件实现断点续传、秒传和分片上传的示例代码,同时还实现了上传过的分片不再上传的功能。
```
import React, { useState } from 'react';
import axios from 'axios';
function Upload() {
const [selectedFile, setSelectedFile] = useState(null);
const [uploaded, setUploaded] = useState(false);
const [progress, setProgress] = useState(0);
const handleFileSelect = (event) => {
setSelectedFile(event.target.files[0]);
};
const handleUpload = async () => {
if (!selectedFile) {
alert('请选择文件');
return;
}
const fileSize = selectedFile.size;
const fileName = selectedFile.name;
// 下面这段代码可以判断文件是否已经上传过,如果已经上传过,
// 则直接返回,不需要再次上传,实现秒传功能
const res = await axios.get(`/check-file/${fileName}`);
if (res.data && res.data.isUploaded) {
setUploaded(true);
return;
}
// 计算需要分片的总数
const chunkSize = 2 * 1024 * 1024; // 每个分片的大小为2MB
const totalChunks = Math.ceil(fileSize / chunkSize);
// 生成上传任务ID
const taskId = Math.random().toString(36).slice(2);
// 创建上传任务
await axios.post('/create-task', {
taskId,
fileName,
fileSize,
totalChunks,
});
// 获取已上传的分片列表
const uploadedChunksRes = await axios.get(`/get-uploaded-chunks/${taskId}`);
const uploadedChunks = uploadedChunksRes.data;
// 上传未上传过的分片
let uploadedChunksCount = 0;
for (let i = 0; i < totalChunks; i++) {
if (uploadedChunks.includes(i)) {
uploadedChunksCount += 1;
continue;
}
const start = i * chunkSize;
const end = Math.min(start + chunkSize, fileSize);
const chunk = selectedFile.slice(start, end);
const formData = new FormData();
formData.append('file', chunk, fileName);
formData.append('taskId', taskId);
formData.append('chunkIndex', i);
await axios.post('/upload-chunk', formData, {
onUploadProgress: (progressEvent) => {
const loaded = progressEvent.loaded;
const total = progressEvent.total;
const percent = Math.round((loaded / total) * 100);
setProgress(percent);
},
});
uploadedChunksCount += 1;
// 每上传10个分片,就更新一次数据库中的上传进度
if (uploadedChunksCount % 10 === 0) {
await axios.post('/update-progress', {
taskId,
progress: Math.round((uploadedChunksCount / totalChunks) * 100),
});
}
}
// 标记文件上传完成
await axios.post('/upload-finish', {
taskId,
});
setUploaded(true);
};
return (
<div>
<input type="file" onChange={handleFileSelect} />
<button onClick={handleUpload}>上传</button>
{progress > 0 && progress < 100 && (
<p>上传进度:{progress}%</p>
)}
{uploaded && (
<p>上传完成</p>
)}
</div>
);
}
export default Upload;
```
在上面的代码中,我们首先通过`useState`来管理组件状态。当用户选择了文件后,我们会通过`handleFileSelect`函数将文件信息保存到`selectedFile`状态中。然后,当用户点击上传按钮时,我们会根据文件大小和文件名等信息,计算出需要分片的总数,并生成一个上传任务ID。接下来,我们会先检查文件是否已经上传过,如果已经上传过,则直接返回,实现秒传功能。如果文件没有上传过,则创建一个上传任务,并获取已经上传过的分片列表。然后,我们会循环上传每个未上传过的分片。每上传完10个分片,就会更新一次数据库中的上传进度。最后,当所有分片上传完成后,我们会标记文件上传完成,并显示上传完成的提示信息。
需要注意的是,在上面的代码中,我们使用了`axios`库来发起HTTP请求,但是具体的上传和断点续传逻辑需要配合后端实现。此外,我们还需要在后端实现获取已上传的分片列表的接口,并将已上传的分片保存到数据库中,以便前端在上传时进行判断。