下面我将基于上文的技术方案,提供详细的使用方法和组件封装方案。
npm install file-saver jszip
utils/batchDownload.js
文件:import { saveAs } from 'file-saver';
import JSZip from 'jszip';
/**
* 批量下载文件并打包为ZIP
* @param {Array} fileList - 文件列表,每个元素包含url和name属性
* @param {String} zipName - 可选,ZIP文件名称
*/
export const batchDownload = async (fileList, zipName = '批量下载.zip') => {
if (!fileList || fileList.length === 0) {
alert('请选择要下载的文件');
return;
}
const zip = new JSZip();
const failedFiles = [];
// 逐个下载文件并添加到ZIP
for (const file of fileList) {
try {
const response = await fetch(file.url);
if (!response.ok) throw new Error(`下载失败: ${response.statusText}`);
const blob = await response.blob();
const fileName = file.name || file.url.split('/').pop();
zip.file(fileName, blob);
} catch (error) {
console.error(`文件 ${file.name || file.url} 下载失败:`, error);
failedFiles.push(file.name || file.url);
}
}
// 生成并下载ZIP文件
const content = await zip.generateAsync({ type: 'blob' });
saveAs(content, zipName);
// 提示下载失败的文件
if (failedFiles.length > 0) {
alert(`以下文件下载失败:\n${failedFiles.join('\n')}`);
}
};
import { batchDownload } from '@/utils/batchDownload';
export default {
data() {
return {
selectedFiles: [
{ url: 'https://example.com/file1.pdf', name: '文档1.pdf' },
{ url: 'https://example.com/file2.jpg', name: '图片2.jpg' }
]
};
},
methods: {
async handleBatchDownload() {
await batchDownload(this.selectedFiles, '资料合集.zip');
}
}
};
import axios from 'axios';
export default {
methods: {
async batchDownloadByBackend() {
const fileIds = this.selectedFiles.map(file => file.id);
try {
const response = await axios.post('/api/downloadBatch', { fileIds }, {
responseType: 'blob'
});
const url = window.URL.createObjectURL(new Blob([response.data]));
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', '批量下载.zip');
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
} catch (error) {
console.error('下载失败', error);
this.$message.error('批量下载失败,请稍后重试');
}
}
}
};
下面是一个基于方案一的可复用组件实现:
<template>
<div class="batch-download">
<el-button
:loading="isLoading"
@click="handleDownload"
:disabled="selectedFiles.length === 0"
>
<i class="el-icon-download"></i> 批量下载
<span v-if="selectedFiles.length > 0" class="file-count">({{selectedFiles.length}})</span>
</el-button>
<el-progress
v-if="isLoading && progress > 0"
:percentage="progress"
:color="progressColor"
status="active"
></el-progress>
<el-alert
v-if="failedFiles.length > 0"
title="部分文件下载失败"
type="warning"
:description="failedFiles.join('、')"
show-icon
></el-alert>
</div>
</template>
<script>
import { batchDownload } from '@/utils/batchDownload';
export default {
name: 'BatchDownload',
props: {
// 待下载的文件列表
files: {
type: Array,
default: () => []
},
// 已选择的文件ID列表
selectedFileIds: {
type: Array,
default: () => []
},
// ZIP文件名
zipName: {
type: String,
default: '批量下载.zip'
}
},
data() {
return {
isLoading: false,
progress: 0,
failedFiles: [],
timer: null
};
},
computed: {
// 当前选中的文件
selectedFiles() {
if (!this.selectedFileIds || this.selectedFileIds.length === 0) {
return this.files;
}
return this.files.filter(file => this.selectedFileIds.includes(file.id));
},
// 进度条颜色
progressColor() {
if (this.progress < 50) return '#20a0ff';
if (this.progress < 80) return '#ff9900';
return '#67c23a';
}
},
methods: {
async handleDownload() {
if (this.selectedFiles.length === 0) {
this.$message.warning('请选择要下载的文件');
return;
}
this.isLoading = true;
this.progress = 0;
this.failedFiles = [];
// 模拟进度条
this.timer = setInterval(() => {
if (this.progress < 90) {
this.progress += Math.random() * 10;
}
}, 300);
try {
await batchDownload(this.selectedFiles, this.zipName);
this.$message.success('下载任务已启动');
} catch (error) {
console.error('批量下载出错:', error);
this.$message.error('批量下载失败,请稍后重试');
} finally {
this.isLoading = false;
this.progress = 100;
clearInterval(this.timer);
// 发送下载完成事件
this.$emit('download-complete', {
total: this.selectedFiles.length,
failed: this.failedFiles.length
});
}
}
},
beforeDestroy() {
clearInterval(this.timer);
}
};
</script>
<style scoped>
.batch-download {
display: inline-flex;
align-items: center;
gap: 10px;
}
.file-count {
margin-left: 5px;
font-size: 12px;
color: #606266;
}
</style>
<template>
<div class="file-management">
<el-table
:data="fileList"
@selection-change="handleSelectionChange"
>
<el-table-column type="selection" width="55"></el-table-column>
<el-table-column label="文件名" prop="name"></el-table-column>
<el-table-column label="大小" prop="size"></el-table-column>
<el-table-column label="操作" width="120">
<template #default="scope">
<el-button
size="mini"
@click="downloadSingleFile(scope.row)"
>
下载
</el-button>
</template>
</el-table-column>
</el-table>
<BatchDownload
:files="fileList"
:selectedFileIds="selectedIds"
zipName="项目资料.zip"
@download-complete="handleDownloadComplete"
/>
</div>
</template>
<script>
import BatchDownload from '@/components/BatchDownload.vue';
export default {
components: { BatchDownload },
data() {
return {
fileList: [],
selectedIds: []
};
},
methods: {
handleSelectionChange(selection) {
this.selectedIds = selection.map(item => item.id);
},
handleDownloadComplete(result) {
console.log('下载完成统计:', result);
},
downloadSingleFile(file) {
// 单文件下载逻辑
}
}
};
</script>
对于大文件或大量文件的下载,可以使用fetch
的ReadableStream
API监控下载进度:
// 在batchDownload函数中添加进度监控
const response = await fetch(file.url);
const reader = response.body.getReader();
const contentLength = response.headers.get('Content-Length');
let receivedLength = 0;
const chunks = [];
while (true) {
const { done, value } = await reader.read();
if (done) break;
chunks.push(value);
receivedLength += value.length;
// 更新进度
const percent = Math.round((receivedLength / contentLength) * 100);
this.$emit('download-progress', { file, percent });
}
const blob = new Blob(chunks);
对于特别大的文件,可以结合后端实现断点续传功能:
// 带断点续传的下载函数
async downloadFileWithResume(url, fileName) {
const chunkSize = 1024 * 1024; // 1MB
let downloadedBytes = 0;
// 检查是否有已下载的部分
const storedProgress = localStorage.getItem(`download_progress_${fileName}`);
if (storedProgress) {
downloadedBytes = parseInt(storedProgress);
}
const response = await fetch(url, {
headers: { Range: `bytes=${downloadedBytes}-` }
});
const totalBytes = parseInt(response.headers.get('Content-Length')) + downloadedBytes;
const reader = response.body.getReader();
const writer = fs.createWriteStream(fileName, { flags: 'a' });
while (true) {
const { done, value } = await reader.read();
if (done) break;
writer.write(value);
downloadedBytes += value.length;
// 保存下载进度
localStorage.setItem(`download_progress_${fileName}`, downloadedBytes);
// 更新进度条
const percent = Math.round((downloadedBytes / totalBytes) * 100);
this.$emit('download-progress', { fileName, percent });
}
// 下载完成,清除进度记录
localStorage.removeItem(`download_progress_${fileName}`);
}
通过以上封装和使用方法,你可以在Vue项目中快速集成批量下载功能,并根据实际需求进行定制扩展。
Vue, 文件批量下载,组件封装,使用方法,优化方案,前端开发,JavaScript,Web 开发,组件化开发,代码优化,批量操作,下载功能,前端组件,Vue 组件,热门技术
资源地址:
https://pan.quark.cn/s/2d75d693deb4
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有