今天我们来聊聊前端如何实现 文件上传进度条。无论是上传图片、视频还是其他文件,进度条都是提升用户体验的重要一环。
1. 为什么需要上传进度条?
- 提升用户体验:让用户直观地看到上传进度,避免焦虑。
- 增强交互性:提供实时反馈,提升用户参与感。
- 便于调试:帮助开发者监控上传过程,快速定位问题。
2. 实现思路
- 监听上传进度 :使用
XMLHttpRequest
或Fetch API
监听上传进度。 - 计算进度百分比:根据已上传的字节数和总字节数计算进度。
- 更新 UI:将进度百分比实时显示在页面上。
3. 使用 XMLHttpRequest 实现
XMLHttpRequest
提供了 upload.onprogress
事件,可以监听上传进度。
(1)HTML 部分
bash
<input type="file" id="file-input" />
<button id="upload-btn">上传</button>
<div id="progress-bar" style="width: 0%; height: 20px; background: green;"></div>
<div id="progress-text">0%</div>
(2)JavaScript 部分
ini
document.getElementById('upload-btn').addEventListener('click', () => {
const file = document.getElementById('file-input').files[0];
if (!file) {
alert('请选择文件');
return;
}
const xhr = new XMLHttpRequest();
const formData = new FormData();
formData.append('file', file);
// 监听上传进度
xhr.upload.onprogress = (event) => {
if (event.lengthComputable) {
const percent = (event.loaded / event.total) * 100;
updateProgress(percent);
}
};
// 上传完成
xhr.onload = () => {
if (xhr.status === 200) {
alert('文件上传成功');
} else {
alert('文件上传失败');
}
};
// 上传失败
xhr.onerror = () => {
alert('文件上传出错');
};
// 开始上传
xhr.open('POST', '/upload', true);
xhr.send(formData);
});
// 更新进度条
function updateProgress(percent) {
const progressBar = document.getElementById('progress-bar');
const progressText = document.getElementById('progress-text');
progressBar.style.width = `${percent}%`;
progressText.textContent = `${percent.toFixed(2)}%`;
}
4. 使用 Fetch API 实现
Fetch API
本身不支持直接监听上传进度,但可以通过 ReadableStream
和 TransformStream
实现。
(1)HTML 部分
bash
<input type="file" id="file-input" />
<button id="upload-btn">上传</button>
<div id="progress-bar" style="width: 0%; height: 20px; background: green;"></div>
<div id="progress-text">0%</div>
(2)JavaScript 部分
ini
document.getElementById('upload-btn').addEventListener('click', async () => {
const file = document.getElementById('file-input').files[0];
if (!file) {
alert('请选择文件');
return;
}
const reader = file.stream().getReader();
let uploadedSize = 0;
const totalSize = file.size;
// 创建自定义的 ReadableStream
const readableStream = new ReadableStream({
async start(controller) {
while (true) {
const { done, value } = await reader.read();
if (done) {
controller.close();
break;
}
uploadedSize += value.length;
updateProgress((uploadedSize / totalSize) * 100);
controller.enqueue(value);
}
},
});
// 上传文件
const response = await fetch('/upload', {
method: 'POST',
headers: {
'Content-Type': 'application/octet-stream',
},
body: readableStream,
});
if (response.ok) {
alert('文件上传成功');
} else {
alert('文件上传失败');
}
});
// 更新进度条
function updateProgress(percent) {
const progressBar = document.getElementById('progress-bar');
const progressText = document.getElementById('progress-text');
progressBar.style.width = `${percent}%`;
progressText.textContent = `${percent.toFixed(2)}%`;
}
5. 使用第三方库
如果不想手动实现,可以使用以下第三方库:
- Axios:支持上传进度监听。
- Uppy:功能强大的文件上传库,内置进度条。
Axios 示例
javascript
import axios from 'axios';
document.getElementById('upload-btn').addEventListener('click', () => {
const file = document.getElementById('file-input').files[0];
if (!file) {
alert('请选择文件');
return;
}
const formData = new FormData();
formData.append('file', file);
axios.post('/upload', formData, {
onUploadProgress: (progressEvent) => {
const percent = (progressEvent.loaded / progressEvent.total) * 100;
updateProgress(percent);
},
})
.then(() => alert('文件上传成功'))
.catch(() => alert('文件上传失败'));
});
// 更新进度条
function updateProgress(percent) {
const progressBar = document.getElementById('progress-bar');
const progressText = document.getElementById('progress-text');
progressBar.style.width = `${percent}%`;
progressText.textContent = `${percent.toFixed(2)}%`;
}
6. 优化建议
- 断点续传:记录已上传的字节数,上传失败时从中断处继续上传。
- 分片上传:将大文件切割成多个分片,提升上传效率和稳定性。
- 多文件上传:支持同时上传多个文件,并分别显示进度。
- 取消上传:提供取消上传的功能,提升用户体验。
总结
通过监听上传进度并实时更新 UI,可以实现文件上传进度条。无论是使用 XMLHttpRequest
、Fetch API
还是第三方库,都可以轻松实现这一功能。结合断点续传、分片上传等优化手段,可以进一步提升上传体验!