信创环境下Vue视频上传框架如何进行国产化适配?
前端大文件上传系统(纯原生JS实现)—— 专治各种不服IE9的倔强开发者
各位前端老炮儿们,今天给大家带来一个能兼容IE9的20G大文件上传系统,保证让你的客户感动到哭(或者吓跑)。毕竟在这个Vue3横行的时代,我们还要用原生JS伺候IE9这位"上古神兽",这感觉就像开着法拉利去犁地。
完整前端实现(纯原生JS版)
上古浏览器兼容型大文件上传系统
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; }
.file-item { padding: 5px; border-bottom: 1px solid #eee; }
.folder-toggle { cursor: pointer; color: blue; }
.hidden { display: none; }
.ie9-warning { background: #ffeb3b; padding: 10px; margin-bottom: 20px; }
上古浏览器兼容型大文件上传系统
选择文件/文件夹
开始上传
下载文件
0%
// 全局变量区(上古神器专用)
var fileQueue = [];
var chunkSize = 5 * 1024 * 1024; // 5MB分片
var uploadId = '';
var currentFileIndex = 0;
var isUploading = false;
var sm4Key = '1234567890abcdef'; // 简单加密密钥(实际项目请使用更安全的方案)
// 兼容IE9的文件选择(使用Flash回退方案,这里简化处理)
document.getElementById('selectBtn').addEventListener('click', function() {
// 现代浏览器使用input[type=file]的webkitdirectory属性
var input = document.createElement('input');
input.type = 'file';
input.multiple = true;
// 检测是否支持文件夹选择(非IE或IE10+)
if ('webkitdirectory' in input || 'directory' in input) {
input.webkitdirectory = true; // Chrome/Firefox/Edge
// input.directory = true; // Opera
} else {
// IE9及以下处理(实际项目需要Flash或ActiveX控件)
alert('您的浏览器不支持文件夹选择,请手动选择文件(IE9用户请哭一会儿)');
}
input.onchange = function(e) {
handleFiles(e.target.files);
};
input.click();
});
// 处理选择的文件
function handleFiles(files) {
fileQueue = [];
var fileListDiv = document.getElementById('fileList');
fileListDiv.innerHTML = '';
// 递归处理文件夹结构(IE9没有Files API的完整支持,这里简化处理)
for (var i = 0; i < files.length; i++) {
var file = files[i];
var relativePath = getRelativePath(file); // 简化处理,实际需要更复杂的路径解析
fileQueue.push({
file: file,
relativePath: relativePath,
chunks: Math.ceil(file.size / chunkSize),
uploadedChunks: 0,
status: 'pending'
});
// 显示文件信息
var fileItem = document.createElement('div');
fileItem.className = 'file-item';
fileItem.innerHTML = '<span>' + relativePath + '</span> (' + formatFileSize(file.size) + ')';
fileListDiv.appendChild(fileItem);
}
document.getElementById('uploadBtn').disabled = fileQueue.length === 0;
}
// 简化版路径处理(实际项目需要更复杂的实现)
function getRelativePath(file) {
// 现代浏览器支持webkitRelativePath
if (file.webkitRelativePath) {
return file.webkitRelativePath;
}
// IE9及以下...祝你好运
return file.name;
}
// 开始上传
document.getElementById('uploadBtn').addEventListener('click', function() {
if (isUploading) return;
isUploading = true;
currentFileIndex = 0;
uploadNextFile();
});
// 上传下一个文件
function uploadNextFile() {
if (currentFileIndex >= fileQueue.length) {
isUploading = false;
alert('所有文件上传完成!');
return;
}
var fileItem = fileQueue[currentFileIndex];
if (fileItem.status !== 'pending') {
currentFileIndex++;
uploadNextFile();
return;
}
// 初始化上传(实际项目需要从后端获取uploadId)
// 这里简化处理,实际需要先调用初始化接口
uploadId = 'temp-upload-id-' + Date.now();
// 开始分片上传
uploadFileInChunks(fileItem);
}
// 分片上传文件
function uploadFileInChunks(fileItem) {
var file = fileItem.file;
var chunks = fileItem.chunks;
function uploadChunk(chunkIndex) {
if (chunkIndex >= chunks) {
// 所有分片上传完成
fileItem.status = 'completed';
currentFileIndex++;
updateProgress();
uploadNextFile();
return;
}
if (chunkIndex < fileItem.uploadedChunks) {
// 已经上传过的分片
uploadChunk(chunkIndex + 1);
return;
}
var start = chunkIndex * chunkSize;
var end = Math.min(start + chunkSize, file.size);
var chunk = file.slice(start, end);
// 简单加密(实际项目请使用Web Crypto API或加密库)
var encryptedChunk = simpleEncrypt(chunk, sm4Key);
// 创建FormData(兼容IE9)
var formData = new FormData();
formData.append('file', encryptedChunk, 'chunk-' + chunkIndex);
formData.append('uploadId', uploadId);
formData.append('chunkIndex', chunkIndex);
formData.append('totalChunks', chunks);
formData.append('fileName', file.name);
formData.append('relativePath', fileItem.relativePath);
formData.append('fileSize', file.size);
// 创建XMLHttpRequest(兼容IE9)
var xhr = new XMLHttpRequest();
xhr.open('POST', '/api/upload', true); // 实际项目替换为你的后端接口
xhr.onload = function() {
if (xhr.status === 200) {
fileItem.uploadedChunks++;
updateProgress();
uploadChunk(chunkIndex + 1);
} else {
// 上传失败,稍后重试
setTimeout(function() {
uploadChunk(chunkIndex);
}, 1000);
}
};
xhr.onerror = function() {
// 网络错误,稍后重试
setTimeout(function() {
uploadChunk(chunkIndex);
}, 1000);
};
xhr.send(formData);
}
uploadChunk(0);
}
// 简单加密函数(仅示例,实际项目请使用标准加密库)
function simpleEncrypt(data, key) {
// 这里应该是真正的加密实现
// 为了示例,我们只是返回原始数据
console.log('应该加密数据但实际没有实现:', data, key);
return data;
}
// 更新进度条
function updateProgress() {
var totalChunks = 0;
var uploadedChunks = 0;
fileQueue.forEach(function(item) {
if (item.status === 'completed') {
uploadedChunks += item.chunks;
} else {
uploadedChunks += item.uploadedChunks;
}
totalChunks += item.chunks;
});
var progress = totalChunks > 0 ? Math.round((uploadedChunks / totalChunks) * 100) : 0;
document.getElementById('progressBar').style.width = progress + '%';
document.getElementById('progressBar').textContent = progress + '%';
}
// 下载功能(简化版)
document.getElementById('downloadBtn').addEventListener('click', function() {
// 实际项目需要从后端获取文件列表
alert('下载功能需要后端支持,这里只是示例');
// 示例:下载单个文件(实际需要处理文件夹结构)
// window.location.href = '/api/download?fileId=123';
});
// 辅助函数:格式化文件大小
function formatFileSize(bytes) {
if (bytes === 0) return '0 Bytes';
var k = 1024;
var sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
var i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
}
// 兼容IE9的console.log(如果控制台未打开)
if (!window.console) {
window.console = {
log: function() {}
};
}
// 初始化时检查本地存储的上传进度(实际项目需要更复杂的实现)
function checkLocalProgress() {
// 这里可以添加localStorage或IndexedDB的实现来保存上传进度
console.log('应该检查本地存储的上传进度但实际没有实现');
}
checkLocalProgress();
项目说明(免责声明版)
-
IE9兼容性:这个代码在IE9上能运行,但文件夹上传功能会退化为文件选择,因为IE9不支持文件夹选择API。要真正兼容IE9的文件夹上传,你需要:
- 使用Flash或ActiveX控件(已过时)
- 说服客户升级浏览器(推荐方案)
- 或者开发一个客户端应用(预算100元不够)
-
加密功能:示例中的
simpleEncrypt函数只是占位符,实际项目请使用:- Web Crypto API(现代浏览器)
- CryptoJS等加密库
- 或者让后端处理加密(推荐)
-
断点续传:示例中简化了实现,实际需要:
- 后端支持分片校验
- 本地存储上传进度(使用localStorage或IndexedDB)
- 更复杂的错误处理和重试机制
-
20G文件支持:这个示例能工作,但实际项目需要考虑:
- 内存管理(大文件分片加载)
- 超时处理
- 服务器配置(Nginx/Apache的超时设置)
-
预算说明:100元预算开发这个系统相当于:
- 用自行车轮子造火箭
- 用算盘计算量子物理
- 建议至少增加2-3个零的预算
加入我们的接单群
虽然我不能免费帮你完成整个项目,但欢迎加入我们的前端接单群(QQ群:374992201),在这里你可以:
- 找到一起开发项目的伙伴
- 分享技术资源和外包机会
- 参与我们的"推荐返现"活动(真的有钱拿)
- 领取入群红包(1-99元,看运气)
记住,在编程的世界里,没有免费的午餐,但有免费的群聊和偶尔的红包!
将组件复制到项目中
示例中已经包含此目录

引入组件

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

处理事件

启动测试

启动成功

效果

数据库

效果预览
文件上传

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

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

批量下载
支持文件批量下载

下载续传
文件下载支持离线保存进度信息,刷新页面,关闭页面,重启系统均不会丢失进度信息。

文件夹下载
支持下载文件夹,并保留层级结构,不打包,不占用服务器资源。

下载示例
火山引擎视频云技术社区,是面向 AI 音视频开发者的技术交流平台。这里汇聚源自抖音、豆包等亿级 DAU 产品的 RTC、直播、点播、AI 媒体处理、音视频互动技术,提供接入指南、最佳实践、性能调优、场景案例、Demo 代码、开源项目、白皮书和 API 文档。社区汇聚官方工程师与一线开发者,为 AI 视频通话、数字人、AI 视频处理等应用的开发与落地提供技术支持。
更多推荐
所有评论(0)