当前位置: 首页 > news >正文

Vue如何通过WebUploader优化病历图片的多线程分片断点续传与传输加密插件?

前端老炮的20G文件夹上传大冒险(附部分代码)

各位前端同仁们,我是老张,一个在辽宁苦哈哈写代码的"前端民工"。最近接了个活,客户要求用原生JS实现20G文件夹上传下载,还要支持IE9!这简直是要了我这把老骨头的命啊!不过为了那100块预算(划掉),为了技术理想,我决定拼了!

项目背景(哭诉版)

客户要求:

  • 20G大文件上传(这是要上传整个硬盘吗?)
  • 文件夹上传保留层级结构(1000个分类的文件,这是要搞文件管理系统吗?)
  • 支持SM4/AES加密(这是要搞国家机密吗?)
  • 断点续传(用户重启电脑都不能丢进度,这是要我做操作系统吗?)
  • 兼容IE9(现在还有人用IE9?哦,是Windows 7用户,好吧,我理解)
  • 预算100元以内(这连买杯咖啡都不够啊!)
  • 7*24小时技术支持(这是要把我当24小时客服吗?)
  • 3年免费维护(这是要签终身合同吗?)

技术选型(妥协版)

经过深思熟虑,我决定:

  • 前端:Vue3 + 原生JS(因为客户说不能用WebUploader)
  • 后端:SpringBoot(但我不写后端代码,哈哈)
  • 加密:crypto-js(因为IE9不支持Web Crypto API)
  • 文件分片:自己实现(因为找不到现成的IE9兼容方案)

部分前端代码(救命版)

以下是文件夹上传的核心代码,其他功能你们自己实现吧(逃):

20G文件夹上传神器(IE9兼容版) body { font-family: 'Microsoft YaHei', sans-serif; margin: 20px; } .progress-container { width: 100%; background: #f0f0f0; margin: 10px 0; } .progress-bar { height: 20px; background: #4CAF50; width: 0%; text-align: center; line-height: 20px; color: white; } .file-list { margin-top: 20px; border: 1px solid #ddd; padding: 10px; max-height: 300px; overflow-y: auto; } 20G文件夹上传神器(IE9兼容版) 选择文件夹 开始上传 暂停上传 0% 文件列表: // 全局变量(IE9兼容的"类"实现) var FileUploader = { files: [], chunkSize: 5 * 1024 * 1024, // 5MB分片 uploadId: null, paused: false, // 初始化(IE9兼容版) init: function() { document.getElementById('fileInput').addEventListener('change', this.handleFileSelect.bind(this)); // 模拟断点续传的本地存储(IE9用userData或cookie,这里简化用localStorage) if (!localStorage.getItem('uploadProgress')) { localStorage.setItem('uploadProgress', JSON.stringify({})); } }, // 处理文件夹选择(IE9兼容版) handleFileSelect: function(e) { this.files = []; var fileList = e.target.files; // 递归构建文件树(IE9没有File.webkitRelativePath,需要特殊处理) for (var i = 0; i < fileList.length; i++) { var file = fileList[i]; // 这里简化处理,实际需要解析webkitRelativePath或手动构建路径 // 兼容IE9的替代方案:让用户先压缩成zip...(开玩笑的) this.files.push({ file: file, path: file.name, // 实际应该用webkitRelativePath uploaded: 0, total: file.size, chunks: Math.ceil(file.size / this.chunkSize), uploadedChunks: 0 }); } this.renderFileList(); }, // 渲染文件列表(IE9兼容版) renderFileList: function() { var list = document.getElementById('fileList'); list.innerHTML = ''; for (var i = 0; i < this.files.length; i++) { var file = this.files[i]; var item = document.createElement('li'); item.innerHTML = file.path + ' (' + this.formatFileSize(file.uploaded) + '/' + this.formatFileSize(file.total) + ')'; list.appendChild(item); } }, // 格式化文件大小(IE9兼容版) formatFileSize: function(bytes) { if (bytes === 0) return '0 Bytes'; var k = 1024; var sizes = ['Bytes', 'KB', 'MB', 'GB']; var i = Math.floor(Math.log(bytes) / Math.log(k)); return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]; }, // 开始上传(IE9兼容版) startUpload: function() { if (this.files.length === 0) { alert('请先选择文件夹'); return; } this.paused = false; this.uploadId = new Date().getTime(); // 简单生成上传ID // 加载之前的上传进度 var progressData = JSON.parse(localStorage.getItem('uploadProgress')); for (var i = 0; i < this.files.length; i++) { var file = this.files[i]; var fileId = file.path; // 实际应该用更唯一的ID // 如果有之前的上传记录,从断点继续 if (progressData[fileId] && progressData[fileId].uploadId === this.uploadId) { file.uploaded = progressData[fileId].uploaded; file.uploadedChunks = progressData[fileId].uploadedChunks; } else { progressData[fileId] = { uploadId: this.uploadId, uploaded: 0, uploadedChunks: 0 }; } } localStorage.setItem('uploadProgress', JSON.stringify(progressData)); this.uploadNextChunk(); }, // 上传下一个分片(IE9兼容版) uploadNextChunk: function() { if (this.paused) return; var fileToUpload = null; var fileIndex = -1; // 查找下一个需要上传的分片 for (var i = 0; i < this.files.length; i++) { var file = this.files[i]; if (file.uploadedChunks < file.chunks) { fileToUpload = file; fileIndex = i; break; } } if (!fileToUpload) { alert('上传完成!'); return; } var chunkIndex = fileToUpload.uploadedChunks; var start = chunkIndex * this.chunkSize; var end = Math.min(start + this.chunkSize, fileToUpload.total); var chunk = fileToUpload.file.slice(start, end); // 加密分片(IE9兼容版) var encryptedChunk = this.encryptData(chunk, 'secret-key-123'); // 实际应该用用户提供的密钥 // 模拟上传(实际应该用XMLHttpRequest或ActiveXObject for IE9) console.log('上传分片:', fileToUpload.path, '分片', chunkIndex, '/', fileToUpload.chunks); // 更新进度(IE9兼容版) fileToUpload.uploadedChunks++; fileToUpload.uploaded = end; // 保存上传进度 var progressData = JSON.parse(localStorage.getItem('uploadProgress')); var fileId = fileToUpload.path; progressData[fileId] = { uploadId: this.uploadId, uploaded: fileToUpload.uploaded, uploadedChunks: fileToUpload.uploadedChunks }; localStorage.setItem('uploadProgress', JSON.stringify(progressData)); // 更新UI this.renderFileList(); this.updateProgressBar(); // 继续上传下一个分片(使用setTimeout模拟异步) var self = this; setTimeout(function() { self.uploadNextChunk(); }, 100); // 模拟网络延迟 }, // 加密数据(IE9兼容版) encryptData: function(data, key) { // 实际应该用SM4或AES,这里简化用CryptoJS的AES // IE9需要额外处理ArrayBuffer到WordArray的转换 if (data instanceof Blob) { return new Promise(function(resolve) { var reader = new FileReader(); reader.onload = function(e) { var words = CryptoJS.enc.Latin1.parse(e.target.result); var encrypted = CryptoJS.AES.encrypt(words, key).toString(); resolve(encrypted); }; reader.readAsBinaryString(data); }); } // 简化处理,实际需要更复杂的实现 return CryptoJS.AES.encrypt(data, key).toString(); }, // 暂停上传(IE9兼容版) pauseUpload: function() { this.paused = true; alert('上传已暂停'); }, // 更新进度条(IE9兼容版) updateProgressBar: function() { var totalUploaded = this.files.reduce(function(sum, file) { return sum + file.uploaded; }, 0); var totalSize = this.files.reduce(function(sum, file) { return sum + file.total; }, 0); var percent = Math.round((totalUploaded / totalSize) * 100); document.getElementById('progressBar').style.width = percent + '%'; document.getElementById('progressBar').innerHTML = percent + '%'; } }; // 初始化(页面加载时执行) window.onload = function() { FileUploader.init(); // 兼容IE9的console.log(IE9没有console对象时) if (!window.console) { window.console = { log: function() {} }; } }; // 暴露全局方法(IE9兼容) window.startUpload = function() { FileUploader.startUpload(); }; window.pauseUpload = function() { FileUploader.pauseUpload(); };

开发心得(吐槽版)

  1. IE9兼容性:这简直是一场噩梦!没有File API,没有Promise,没有const/let,没有箭头函数…我感觉自己在用石器时代的工具开发火箭。

  2. 文件夹上传:现代浏览器有webkitRelativePath,但IE9没有。解决方案?要么让用户先压缩成zip,要么…算了,还是压缩吧(客户肯定不同意)。

  3. 断点续传:localStorage在IE9中只有5MB限制,存储大量上传进度?呵呵,祝你好运。

  4. 加密传输:IE9不支持Web Crypto API,只能用crypto-js这种老库,性能感人。

  5. 20G文件:分片上传是必须的,但IE9的内存管理…算了,别让浏览器崩溃就是胜利。

加入我们的接单群(广告版)

各位同仁,如果你也在为这些奇葩需求头疼,或者想找项目合作,欢迎加入我们的QQ群:374992201

群内福利:

  • 1~99元超级大红包(每天都有)
  • 接单合作机会
  • 技术交流分享
  • 推荐项目拿20%提成
  • 超级会员50%提成(躺着赚钱)

免责声明(求生版)

以上代码仅供娱乐参考,实际项目中请:

  1. 使用成熟的库(如WebUploader、Plupload等)
  2. 考虑使用Flash作为IE9的备选方案
  3. 对于20G文件,建议使用专业的大文件传输方案
  4. 加密传输请使用标准协议(如TLS)而非前端加密
  5. 断点续传最好由后端实现

最后,祝大家项目顺利,少遇奇葩需求!如果真有客户找上门,记得推荐给我啊(手动狗头)!

将组件复制到项目中

示例中已经包含此目录

引入组件

配置接口地址

接口地址分别对应:文件初始化,文件数据上传,文件进度,文件上传完毕,文件删除,文件夹初始化,文件夹删除,文件列表
参考:http://www.ncmem.com/doc/view.aspx?id=e1f49f3e1d4742e19135e00bd41fa3de

处理事件

启动测试

启动成功

效果

数据库

效果预览

文件上传

文件刷新续传

支持离线保存文件进度,在关闭浏览器,刷新浏览器后进行不丢失,仍然能够继续上传

文件夹上传

支持上传文件夹并保留层级结构,同样支持进度信息离线保存,刷新页面,关闭页面,重启系统不丢失上传进度。

下载示例

点击下载完整示例

http://www.cnnetsun.cn/news/2038261.html

相关文章:

  • 揭秘Java静态编译内存暴增之谜:从SubstrateVM GC日志到HeapSnapshot源码逐行剖析(含3个致命内存泄漏POC)
  • 龙邱闪电鼠Q车模减重思路及开源文件分享
  • Swift中的类型安全与动态返回类型
  • 【OpenWrt实战笔记】高通平台Dying Gasp与pstore的协同调试与日志捕获
  • 统计方法在数据科学中的核心应用与实践
  • PySpark中高效展开嵌套数组:避免笛卡尔爆炸的正确实践.txt
  • SQL如何利用JOIN查询进行数据报表汇总_聚合函数与分组连接方法
  • golang如何使用Pebble嵌入式存储_golang Pebble嵌入式存储使用实战
  • SQL如何进行分组后字符串拼接_使用GROUP_CONCAT或STRING_AGG
  • 使用Cypress进行前端测试驱动开发:LINE案例研究
  • 别再只用默认样式了!深度定制Vant Collapse折叠面板的5个实用技巧(Vue2项目)
  • 北斗时间(BDT)与C# DateTime互转实战:处理周内秒、UTC闰秒差与2006起始历元
  • 【Java 25虚拟线程实战白皮书】:2026高并发架构升级必读的5大避坑指南与压测数据验证
  • Python描述符协议实现属性访问控制
  • Docker农业配置黄金标准(农业农村部试点项目技术白皮书核心提炼)
  • 避坑指南:Cesium模型动画那些官方没细说的坑(以火箭模型launchvehicle.glb为例)
  • 告别cc-switch配置混乱!一行命令让两个Claude实例同时使用不同API
  • 3D打印必备:SketchUp STL插件完整使用指南
  • 别再怕IIC时序了!用Verilog状态机清晰图解LM75/AT24C128的读写全过程
  • GD32串口转RS485/422踩坑实录:115200波特率下数据乱码,我如何定位到IP核设计问题?
  • AI在网络安全中的实战应用与ROI优化策略
  • AI Agent:从“科幻概念“到“生活必需品“的进化之路
  • 从SIRAL高度计的三种模式说起:CryoSat-2如何成为海冰厚度测量的‘游戏规则改变者’
  • 【人生底稿・番外篇 09】足球青春篇:37岁老码农,藏在球场晚风里的整条青春长河
  • 浏览器扩展开发插件与内容脚本
  • 如何在30分钟内搭建企业级工作流系统:RuoYi-Flowable-Plus终极指南
  • Minimax算法在策略游戏中的实现与优化
  • 别再死记命令了!用一张图搞懂思科ASA5505防火墙的‘安全等级’与流量放行逻辑
  • 终极指南:3步快速备份微博到PDF,永久保存你的数字记忆
  • 你的1.54寸ST7789V2屏幕只显示单色?手把手教你玩转STM32的SPI驱动与显存管理