好的!下面是一篇结合 Element Plus 的 Vue 3 大文件切片上传 + 断点续传完整实战教程,UI 用的是 Element Plus,结构清晰,语气亲和,适合你直接复制使用。
整理不易,如果本文对你有帮助,欢迎点个【赞 👍】+【收藏 ⭐】+【关注 🧡】
📦 Vue + Element Plus 实战:大文件切片上传 + 断点续传
今天我们来用 Vue 3 + Element Plus,实战开发一个"支持大文件切片上传、断点续传"的文件上传组件,适合上传视频、压缩包、设计图等大文件场景,带完整前端逻辑和 UI 演示👇
🧩一、功能亮点
✅ 文件切片(Blob 分片)
✅ 并发上传,支持进度条
✅ 秒传校验(文件 hash)
✅ 断点续传(跳过已上传)
✅ 合并通知(服务端拼接)
✨二、最终效果图
(上传进度 + 支持断点续传)
🛠️三、完整前端实现(Element Plus 版本)
1️⃣ 安装依赖
bash
npm install element-plus spark-md5
2️⃣ 组件模板(UploadChunk.vue)
html
<template>
<el-card>
<el-upload
:show-file-list="false"
:before-upload="handleBeforeUpload"
:http-request="handleUpload"
drag
accept="*"
>
<i class="el-icon-upload" />
<div class="el-upload__text">将文件拖到此处,或 <em>点击上传</em></div>
</el-upload>
<el-progress
v-if="uploadProgress > 0"
:percentage="uploadProgress"
status="success"
style="margin-top: 20px"
/>
</el-card>
</template>
3️⃣ 脚本逻辑(切片、上传、断点续传)
ts
<script setup>
import { ref } from 'vue'
import SparkMD5 from 'spark-md5'
import { ElMessage } from 'element-plus'
const uploadProgress = ref(0)
const CHUNK_SIZE = 2 * 1024 * 1024 // 2MB
let file = null
let fileHash = ''
let fileChunks = []
// 1. 预处理文件
const handleBeforeUpload = async (rawFile) => {
file = rawFile
fileChunks = createChunks(file)
fileHash = await calculateHash(fileChunks)
return false // 阻止默认上传
}
// 2. 分片
const createChunks = (file) => {
const chunks = []
let cur = 0
while (cur < file.size) {
chunks.push(file.slice(cur, cur + CHUNK_SIZE))
cur += CHUNK_SIZE
}
return chunks
}
// 3. 计算 hash
const calculateHash = (chunks) => {
return new Promise((resolve) => {
const spark = new SparkMD5.ArrayBuffer()
let count = 0
const reader = new FileReader()
const loadNext = () => {
if (count >= chunks.length) {
resolve(spark.end())
return
}
reader.readAsArrayBuffer(chunks[count])
}
reader.onload = (e) => {
spark.append(e.target.result)
count++
loadNext()
}
loadNext()
})
}
// 4. 获取已上传切片(断点续传)
const getUploadedList = async (hash) => {
const res = await fetch(`/uploaded-list?hash=${hash}`)
return res.ok ? await res.json() : []
}
// 5. 上传逻辑
const handleUpload = async () => {
const uploaded = await getUploadedList(fileHash)
const uploadChunk = (chunk, index) => {
const form = new FormData()
form.append('file', chunk)
form.append('filename', file.name)
form.append('chunkIndex', index)
form.append('hash', fileHash)
return fetch('/upload-chunk', {
method: 'POST',
body: form,
})
}
const requests = fileChunks.map((chunk, index) => {
if (uploaded.includes(index)) return null
return uploadChunk(chunk, index)
}).filter(Boolean)
let completed = uploaded.length
const total = fileChunks.length
for (const req of requests) {
await req
completed++
uploadProgress.value = Math.floor((completed / total) * 100)
}
// 通知合并
await fetch('/merge-chunks', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ filename: file.name, hash: fileHash }),
})
ElMessage.success('上传成功 🎉')
uploadProgress.value = 0
}
</script>
📡四、服务端接口规范(参考 Node)
接口说明:
接口 | 描述 |
---|---|
GET /uploaded-list?hash=xxx |
返回已上传切片 index 列表 |
POST /upload-chunk |
接收切片文件,保存到 /tmp/hash/index |
POST /merge-chunks |
合并切片为完整文件,保存在 /uploads/ |
服务端可用 fs-extra
、multer
等处理上传,你需要支持以下流程:
- 创建临时目录保存切片
/tmp/<hash>/index
- 按顺序读取切片合并
fs.appendFileSync
- 合并完成后清理切片
如果你需要我帮你写 Node.js 服务端的完整代码,也可以直接告诉我 👍
🧠五、总结回顾
功能 | 实现点 |
---|---|
切片上传 | Blob.slice() 分片,前端循环上传 |
秒传 | 前端计算 hash,服务端校验是否上传过 |
断点续传 | 获取已上传列表,跳过上传 |
合并通知 | 上传完毕后请求服务端合并接口 |
UI 展示 | Element Plus 上传组件 + 进度条反馈 |