前端如何实现文件上传进度条

今天我们来聊聊前端如何实现 文件上传进度条。无论是上传图片、视频还是其他文件,进度条都是提升用户体验的重要一环。


1. 为什么需要上传进度条?

  • 提升用户体验:让用户直观地看到上传进度,避免焦虑。
  • 增强交互性:提供实时反馈,提升用户参与感。
  • 便于调试:帮助开发者监控上传过程,快速定位问题。

2. 实现思路

  1. 监听上传进度 :使用 XMLHttpRequestFetch API 监听上传进度。
  2. 计算进度百分比:根据已上传的字节数和总字节数计算进度。
  3. 更新 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 本身不支持直接监听上传进度,但可以通过 ReadableStreamTransformStream 实现。

(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. 优化建议

  1. 断点续传:记录已上传的字节数,上传失败时从中断处继续上传。
  2. 分片上传:将大文件切割成多个分片,提升上传效率和稳定性。
  3. 多文件上传:支持同时上传多个文件,并分别显示进度。
  4. 取消上传:提供取消上传的功能,提升用户体验。

总结

通过监听上传进度并实时更新 UI,可以实现文件上传进度条。无论是使用 XMLHttpRequestFetch API 还是第三方库,都可以轻松实现这一功能。结合断点续传、分片上传等优化手段,可以进一步提升上传体验!

相关推荐
小兔崽子去哪了20 分钟前
微信小程序入门
前端·vue.js·微信小程序
独立开阀者_FwtCoder23 分钟前
# 白嫖千刀亲测可行——200刀拿下 Cursor、V0、Bolt和Perplexity 等等 1 年会员
前端·javascript·面试
那小孩儿30 分钟前
?? 、 || 、&&=、||=、??=这些运算符你用对了吗?
前端·javascript
菜鸟码农_Shi38 分钟前
Node.js 如何实现 GitHub 登录(OAuth 2.0)
javascript·node.js
AronTing39 分钟前
10-Spring Cloud Alibaba 之 Dubbo 深度剖析与实战
后端·面试·架构
没资格抱怨42 分钟前
如何在vue3项目中使用 AbortController取消axios请求
前端·javascript·vue.js
雷渊1 小时前
如何保证数据库和Es的数据一致性?
java·后端·面试
总之就是非常可爱1 小时前
🚀 使用 ReadableStream 优雅地处理 SSE(Server-Sent Events)
前端·javascript·后端
ᖰ・◡・ᖳ1 小时前
Web APIs阶段
开发语言·前端·javascript·学习
stoneSkySpace2 小时前
算法——BFS
前端·javascript·算法