这篇文章主要讲解了“如何使用Vue3和ElementPlus前端实现分片上传”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“如何使用Vue3和ElementPlus前端实现分片上传”吧!
将 一个文件 切割为 一系列特定大小的 数据片段,将这些 数据片段 分别上传到服务端;
全部上传完成后,再由服务端将这些 数据片段 合并成为一个完整的资源;
上传过程中,由于外部因素(比如网络波动)导致上传中断,下次上传时会保留该文件的上传进度(断点续传);
包含三部分:
上传组件,使用 el-upload
进度条组件,使用 el-progress
上传完成状态组件,使用 el-input 自定义
<el-form-item label="上传附件" prop="uploadFile"> <el-upload v-if="!editForm.inlineAppVersionModel.fileName" class="upload-demo" drag :show-file-list="false" :action="APP_MANAGEMENT.uploadFile" // 根据项目的接口传递参数 :data="{ applicationId: applicationId, applicationVersion: applicationVersion, bucketName: 'app' }" // 覆盖默认的http请求 :http-request="handleFileUpload" > <el-icon class="el-icon--upload"> <upload-filled /> </el-icon> <div v-if="!progress" class="el-upload__text"> Drop file here or <em>click to upload</em> </div> // 进度条 <el-progress v-else :text-inside="true" :stroke-width="24" :percentage="progress" status="success" /> </el-upload> // 上传成功之后隐藏上传文件组件 <div v-else > <el-input v-model="editForm.inlineAppVersionModel.fileName" readonly> </el-input> <div > <el-button type="primary" :icon="Download" size="small" @click="handleFileDownload" /> <el-button type="primary" :icon="Delete" size="small" @click="handleFileDel" /> </div> </div> </el-form-item>
使用 el-upload 选择文件
选择成功的 回调函数 可以读取文件信息,用于前端校验文件的合法性
前端校验文件合法后,将文件进行切片
通过 请求轮询 把切片传递给后端
在这一步,可以获得文件信息
根据文件信息,对文件进行合法性校验
校验成功后,调用文件切片方法
/** * @description: 选择上传文件 * @param file el-upload 返回的参数 */ const handleFileUpload = async (file: any) => { console.log('el-upload 返回的参数 === ', file.file); // 如果文件合法,则进行分片上传 if (await checkMirrorFile(file)) { // 文件信息 const files = file.file; // 从 0 开始的切片 const shardIndex = 0; // 调用 文件切片 方法 uploadFileSilce(files, shardIndex); // 文件非法,则进行提示 } else { ElMessage.error('请检查文件是否合法!'); } };
校验文件格式
校验文件大小
调用接口,校验磁盘剩余空间大小
/** * @description: 校验文件合法性 */ const checkMirrorFile = async (file) => { // 校验文件格式,支持.zip/.tar const fileType = file.file.name.split('.') if (fileType[fileType.length - 1] !== 'zip' && fileType[fileType.length - 1] !== 'tar') { ElMessage.warning('文件格式错误,仅支持 .zip/.tar') return false } // 校验文件大小 const fileSize = file.file.size; // 文件大小是否超出 2G if (fileSize > 2 * 1024 * 1024 * 1024) { ElMessage.warning('上传文件大小不能超过 2G') return false } // 调用接口校验文件合法性,比如判断磁盘空间大小是否足够 const res = await checkMirrorFileApi() if (res.code !== 200) { ElMessage.warning('暂时无法查看磁盘可用空间,请重试') return false } // 查看磁盘容量大小 if (res.data.diskDevInfos && res.data.diskDevInfos.length > 0) { let saveSize = 0 res.data.diskDevInfos.forEach(i => { // 磁盘空间赋值 if (i.devName === '/dev/mapper/centos-root') { // 返回值为GB,转为字节B saveSize = i.free * 1024 * 1024 * 1024 } }) // 上传的文件大小没有超出磁盘可用空间 if (fileSize < saveSize) { return true } else { ElMessage.warning('文件大小超出磁盘可用空间容量') return false } } else { ElMessage.warning('文件大小超出磁盘可用空间容量') return false } }
此处文件上传用 MD5 进行加密,需要安装依赖 spark-md5
npm i spark-md5
/** * @description: 文件加密处理 */ const getMD5 = (file: any): Promise<string> => new Promise((resolve, reject) => { const spark = new SparkMD5.ArrayBuffer(); // 获取文件二进制数据 const fileReader = new FileReader(); fileReader.readAsArrayBuffer(file); // file 就是获取到的文件 // 异步执行函数 fileReader.addEventListener('load', (e: any) => { spark.append(e.target.result); const md5: string = spark.end(); resolve(md5); }); fileReader.addEventListener('error', (e) => { reject(e); }); });
通过接口合并上传文件,接口需要的参数:
文件名
文件唯一 hash 值
接口合并完成后,前端展示已上传的文件名称
/** * @description: 合并文件 * @param name 文件名 * @param hash 文件唯一 hash 值 * @return 命名名称 */ const composeFile = async (name: string, hash: string) => { console.log('开始文件合并'); const res = await uploadFileMerge({ applicationId: props.applicationId, applicationVersion: props.applicationVersion, bucketName: 'app', fileName: name, hash, }); console.log('后端接口合并文件 ===', res); if (res.status === 200 && res.data.code) { // 合并成功后,调整已上传的文件名称 state.editForm.inlineAppVersionModel.fileName = name; } };
接口轮询 —— 每次携带一个文件切片给后端;后端接受到切片 并 返回成功状态码后,再进行下一次切片上传
/** * @description: 分片函数 * @param file 文件 * @param shardIndex 分片数量 */ const uploadFileSilce = async (file: File, shardIndex: number) => { // 文件名 const { name } = file; // 文件大小 const { size } = file; // 分片大小 const shardSize = 1024 * 1024 * 5; // 文件加密 const hash: string = await getMD5(file); // 分片总数 const shardTotal = Math.ceil(size / shardSize); // 如果 当前分片索引 大于 总分片数 if (shardIndex >= shardTotal) { isAlive.value = false; progress.value = 100; // 合并文件 composeFile(name, hash); return; } // 文件开始结束的位置 const start = shardIndex * shardSize; const end = Math.min(start + shardSize, size); // 开始切割 const packet = file.slice(start, end); // 拼接请求参数 const formData = new FormData(); formData.append('file', packet); formData.append('applicationId', props.applicationId); formData.append('applicationVersion', props.applicationVersion); formData.append('bucketName', 'app'); formData.append('hash', hash); formData.append('shardSize', shardSize as unknown as string); formData.append('seq', shardIndex as unknown as string); // 如果 当前分片索引 小于 总分片数 if (shardIndex < shardTotal) { // 进度条保留两位小数展示 progress.value = Number(((shardIndex / shardTotal) * 100).toFixed(2)) * 1; // 调用文件上传接口 const res = await uploadFile(formData); if (res.status !== 200) { ElMessage.error('上传失败'); progress.value = 0; return; } if (res.status === 200 && res.data.code === 200) { // 这里为所有切片上传成功后进行的操作 console.log('上传成功'); } // eslint-disable-next-line no-param-reassign shardIndex++; // 递归调用 分片函数 uploadFileSilce(file, shardIndex); } };
nginx 默认上传大小为 1MB,若超过 1MB,则需要修改 nginx 配置 解除上传限制
/** * @description: 动态创建 a 标签,实现大文件下载 */ const downloadMirror = async (item) => { let t = { id: item.id, } const res = await downloadMirrorApi(t) if (res.headers["content-disposition"]) { let temp = res.headers["content-disposition"].split(";")[1].split("filename=")[1] let fileName = decodeURIComponent(temp) // 通过创建a标签实现文件下载 let link = document.createElement('a') link.download = fileName link.style.display = 'none' link.href = res.data.msg document.body.appendChild(link) link.click() document.body.removeChild(link) } else { ElMessage({ message: '该文件不存在', type: 'warning', }) } }
感谢各位的阅读,以上就是“如何使用Vue3和ElementPlus前端实现分片上传”的内容了,经过本文的学习后,相信大家对如何使用Vue3和ElementPlus前端实现分片上传这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是亿速云,小编将为大家推送更多相关知识点的文章,欢迎关注!
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。