vue + elementUI 视频分片上传
<template> <div> <el-dialog title="上传视频" :visible.sync="dialogVisible" width="50%" :before-close="handleClose"> <el-upload class="upload-demo" ref="upload" :action="uploadUrl" :before-upload="beforeUpload" :on-progress="handleProgress" :on-success="handleSuccess" :on-error="handleError" :auto-upload="false" :file-list="fileList" list-type="text"> <el-button size="small" type="primary">选取视频</el-button> <div slot="tip" class="el-upload__tip">支持 mp4, avi, mov, wmv, flv 格式,最大不超过 2GB</div> </el-upload> <el-progress :percentage="uploadPercentage" style="margin-top: 15px;"></el-progress> <span slot="footer" class="dialog-footer"> <el-button @click="dialogVisible = false">取 消</el-button> <el-button type="primary" @click="startUpload">上 传</el-button> </span> </el-dialog> </div> </template> <script> export default { data() { return { dialogVisible: false, fileList: [], uploadPercentage: 0, chunkSize: 5 * 1024 * 1024, // 5MB uploadUrl: 'https://your-backend.com/upload' }; }, methods: { beforeUpload(file) { const allowedTypes = ['video/mp4', 'video/avi', 'video/quicktime', 'video/x-ms-wmv', 'video/x-flv']; const isAllowedType = allowedTypes.includes(file.type); const isLt2G = file.size / 1024 / 1024 / 1024 < 2; if (!isAllowedType) { this.$message.error('视频格式不支持!'); return false; } if (!isLt2G) { this.$message.error('视频大小不能超过 2GB!'); return false; } // 分片处理逻辑 this.fileList = this.sliceFile(file); return false; // 阻止默认的上传行为 }, sliceFile(file) { const chunks = []; const totalChunks = Math.ceil(file.size / this.chunkSize); for (let i = 0; i < totalChunks; i++) { const chunk = file.slice(i * this.chunkSize, (i + 1) * this.chunkSize); chunks.push({ chunk, index: i, file }); } return chunks; }, async startUpload() { for (const { chunk, index, file } of this.fileList) { const formData = new FormData(); formData.append('file', chunk); formData.append('index', index); formData.append('fileName', file.name); await this.uploadChunk(formData); } // 合并请求 await this.mergeChunks(this.fileList[0].file.name); }, async uploadChunk(formData) { try { await this.$axios.post(this.uploadUrl, formData, { onUploadProgress: (progressEvent) => { this.uploadPercentage = Math.round((progressEvent.loaded / progressEvent.total) * 100); } }); } catch (error) { console.error('Upload chunk error', error); } }, async mergeChunks(fileName) { try { await this.$axios.post(`${this.uploadUrl}/merge`, { fileName }); this.$message.success('上传成功'); this.dialogVisible = false; this.fileList = []; this.uploadPercentage = 0; } catch (error) { this.$message.error('合并文件失败'); console.error('Merge chunks error', error); } }, handleProgress(event, file, fileList) { this.uploadPercentage = Math.round((event.loaded / event.total) * 100); }, handleSuccess(response, file, fileList) { this.$message.success('上传成功'); this.fileList = []; this.uploadPercentage = 0; this.dialogVisible = false; }, handleError(err, file, fileList) { this.$message.error('上传失败'); this.uploadPercentage = 0; }, handleClose(done) { this.$confirm('确认关闭?') .then(_ => { done(); }) .catch(_ => {}); }, openDialog() { this.dialogVisible = true; } } }; </script> <style scoped> .upload-demo { margin-top: 10px; } </style>