Vue+ElementUI創(chuàng)建一個帶有進度顯示的文件下載和打包組件功能
在現代前端開發(fā)中,用戶體驗至關重要,尤其是在處理文件下載時。為用戶提供實時的下載進度顯示和打包功能,不僅能提升用戶體驗,還能使應用更具專業(yè)性。在本文中,我們將創(chuàng)建一個 Vue 組件,用于顯示文件下載進度,并將下載的文件打包成 ZIP 供用戶下載。
前言
在應用中處理多個文件的下載時,用戶希望看到清晰的進度顯示,同時在下載多個文件時,將它們打包成 ZIP 文件提供下載也是常見需求。通過使用 Vue 和一些實用的 JavaScript 庫,我們可以輕松實現這一功能。
1. 組件功能概述
我們要實現的 Vue 組件具備以下功能:
- 下載多個文件,并實時顯示每個文件的下載進度。
- 打包下載的文件為 ZIP 并顯示打包進度。
- 在進度條內同時顯示文件名稱和下載百分比。
- 下載完成后自動關閉對話框。

2. 導入所需的包
在開始構建組件之前,我們需要先導入一些關鍵的 JavaScript 庫。這些庫將幫助我們實現文件下載、ZIP 打包和文件保存功能。
npm install axios jszip file-saver --save
- axios: 用于執(zhí)行 HTTP 請求,并獲取文件數據。
- jszip: 用于在前端生成 ZIP 文件。
- file-saver: 用于觸發(fā)瀏覽器下載功能,保存生成的 ZIP 文件。
在 Vue 組件中,我們可以通過以下方式導入這些庫:
import axios from 'axios'
import JSZip from 'jszip'
import { saveAs } from 'file-saver'3. 構建基礎組件
我們從構建基礎的 Vue 組件結構開始,該組件將接收文件列表和控制對話框的顯示狀態(tài)。
<template>
<div>
<el-dialog :visible.sync="internalDialogVisible" title="Download Files">
<el-progress v-for="(file, index) in downloadFiles"
style="margin-bottom: 10px;"
:key="index"
:percentage="file.progress"
:text-inside="true"
:stroke-width="26"
:format="formatProgress(file.name)">
</el-progress>
<el-progress :percentage="packProgress"
:stroke-width="26"
:text-inside="true"
status="success"
:format="formatPackingProgress">
</el-progress>
</el-dialog>
</div>
</template>4.實現文件下載與進度顯示
在文件下載過程中,我們需要實時更新進度條,并顯示文件的下載進度。為此,axios 提供了 onDownloadProgress 鉤子,用于在下載過程中獲取進度信息。
const response = await axios.get(file.url, {
responseType: 'blob',
onDownloadProgress: (progressEvent) => {
// 計算下載進度
const progress = Math.round((progressEvent.loaded * 100) / progressEvent.total)
this.$set(this.downloadFiles, index, {
...file,
progress
})
}
})5. 打包文件為 ZIP
在所有文件下載完成后,我們將這些文件打包成 ZIP 格式。通過 JSZip 庫,我們可以輕松實現文件打包,并使用 file-saver 來觸發(fā)瀏覽器下載。
async startDownload () {
try {
const zip = new JSZip()
// 下載所有文件并添加到 zip 中
const downloadPromises = this.downloadFiles.map(async (file) => {
const response = await axios.get(file.url, {
responseType: 'blob'
})
zip.file(file.name, response.data)
})
// 等待所有文件下載完成
await Promise.all(downloadPromises)
// 生成 zip 并觸發(fā)下載
zip.generateAsync({ type: 'blob' }).then((content) => {
saveAs(content, this.zipName + '.zip')
this.$emit('update:dialogVisible', false)
})
} catch (error) {
console.error('Download failed:', error)
}
}6. 控制對話框的顯示與隱藏
為了更好地控制對話框的顯示與隱藏,我們在組件中使用 internalDialogVisible 作為內部控制變量,并通過 watch 監(jiān)聽 dialogVisible 的變化。當對話框打開時,我們啟動下載流程,并在所有操作完成后關閉對話框。
watch: {
dialogVisible (newVal) {
this.internalDialogVisible = newVal
if (newVal) {
this.downloadFiles = this.files.map(file => ({ ...file, progress: 0 }))
this.packProgress = 0
this.startDownload()
}
},
internalDialogVisible (newVal) {
this.$emit('update:dialogVisible', newVal)
}
}7. 可能會遇到的問題:處理跨域請求 (CORS)
在實現文件下載功能時,尤其是當我們從不同的域名或服務器請求文件資源時,可能會遇到跨域資源共享 (CORS) 問題。CORS 是一種瀏覽器安全機制,用于防止惡意網站在用戶不知情的情況下發(fā)起跨域請求。因此,當我們的 Vue 應用從與其源不同的服務器請求資源時,瀏覽器會根據 CORS 規(guī)則來決定是否允許該請求。
7.1 什么是 CORS?
CORS (Cross-Origin Resource Sharing) 是瀏覽器和服務器之間的一種協議,用于控制哪些資源可以通過跨域 HTTP 請求被訪問。它通過添加特定的 HTTP 頭來告知瀏覽器資源是否可以被訪問。
7.2 常見的 CORS 錯誤
當我們在實現文件下載時,如果服務器沒有正確配置 CORS,我們可能會遇到以下錯誤:
Access to XMLHttpRequest at 'https://example.com/file' from origin 'http://localhost:8080' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
這個錯誤說明目標服務器沒有正確配置 Access-Control-Allow-Origin 頭,導致瀏覽器阻止了該請求。
7.3 解決 CORS 問題的方法
服務器端配置:
在理想情況下,我們應當擁有對目標服務器的控制權,并在服務器端配置允許的跨域請求。具體方法是在服務器的響應頭中添加 Access-Control-Allow-Origin,比如:
Access-Control-Allow-Origin: * Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS Access-Control-Allow-Headers: Content-Type, Authorization
這將允許所有來源的跨域請求。當然,我們也可以將 Access-Control-Allow-Origin 設置為特定的域名,以限制允許跨域訪問的來源。
使用代理服務器:
如果我們無法控制目標服務器的配置,可以考慮在開發(fā)環(huán)境中使用代理服務器。通過 Vue CLI 我們可以輕松配置代理,將請求通過代理服務器發(fā)送,從而避免 CORS 問題。以下是 Vue CLI 中的 vue.config.js 配置示例:
module.exports = {
devServer: {
proxy: {
'/api': {
target: 'https://example.com',
changeOrigin: true,
pathRewrite: { '^/api': '' }
}
}
}
}通過這種配置,所有發(fā)往 /api 的請求都會被代理到 https://example.com,從而避免直接跨域請求導致的 CORS 問題。
使用 JSONP:
JSONP (JSON with Padding) 是一種傳統的跨域解決方案,主要用于 GET 請求。然而,由于它僅支持 GET 請求且具有安全風險,現代應用中較少使用。
啟用 CORS 插件:
在開發(fā)環(huán)境中,為了臨時解決 CORS 問題,可以使用瀏覽器插件如 CORS Unblock。不過,這只適用于開發(fā)和調試階段,不推薦在生產環(huán)境中使用。
7.4 說明
CORS 問題是開發(fā)跨域資源請求時不可避免的挑戰(zhàn)之一。在實現文件下載功能時,務必確保服務器配置正確的 CORS 頭,以允許來自我們應用的請求。如果無法控制服務器配置,可以考慮使用代理服務器或其他臨時解決方案。在生產環(huán)境中,最好的做法是從服務器端正確處理 CORS,以確保安全性和可靠性。
8. 完整源代碼
<template>
<div>
<el-dialog :visible.sync="internalDialogVisible"
title="Download Files">
<el-progress v-for="(file, index) in downloadFiles"
style="margin-bottom: 10px;"
:key="index"
:percentage="file.progress"
:text-inside="true"
:stroke-width="26"
:format="formatProgress(file.name)">
</el-progress>
<el-progress :percentage="packProgress"
:stroke-width="26"
:text-inside="true"
status="success"
:format="formatPackingProgress">
</el-progress>
</el-dialog>
</div>
</template>
<script>
import axios from 'axios'
import JSZip from 'jszip'
import { saveAs } from 'file-saver'
export default {
name: 'DownloadManager',
props: {
files: {
type: Array,
required: true
},
dialogVisible: {
type: Boolean,
required: true
},
zipName: {
type: String,
required: true
}
},
data () {
return {
internalDialogVisible: this.dialogVisible,
downloadFiles: this.files.map(file => ({ ...file, progress: 0 })),
packProgress: 0
}
},
methods: {
formatProgress (fileName) {
return percentage => `${fileName} - ${percentage}%`
},
formatPackingProgress (percentage) {
return `Packing Files - ${percentage}%`
},
async startDownload () {
try {
const zip = new JSZip()
// 下載所有文件并添加到 zip 中
const downloadPromises = this.downloadFiles.map(async (file, index) => {
const response = await axios.get(file.url, {
responseType: 'blob',
onDownloadProgress: (progressEvent) => {
// 計算下載進度
const progress = Math.round((progressEvent.loaded * 100) / progressEvent.total)
this.$set(this.downloadFiles, index, {
...file,
progress
})
}
})
zip.file(file.name, response.data)
})
// 等待所有文件下載完成
await Promise.all(downloadPromises)
// 生成 zip 并觸發(fā)下載,同時更新打包進度
zip.generateAsync({ type: 'blob' }, (metadata) => {
this.packProgress = Math.round((metadata.percent))
}).then((content) => {
saveAs(content, this.zipName + '.zip')
this.$emit('update:dialogVisible', false)
})
} catch (error) {
console.error('Download failed:', error)
}
}
},
watch: {
dialogVisible (newVal) {
this.internalDialogVisible = newVal
if (newVal) {
this.downloadFiles = this.files.map(file => ({ ...file, progress: 0 }))
this.packProgress = 0
this.startDownload()
}
},
internalDialogVisible (newVal) {
this.$emit('update:dialogVisible', newVal)
}
}
}
</script>9. 組件調用
要在外部調用這個組件,可以按照以下步驟操作:
9.1 引入并注冊組件
在希望使用這個 DownloadManager 組件的地方引入它,并在父組件中注冊。
假設在一個名為 App.vue 的組件中調用 DownloadManager:
<template>
<div>
<!-- 其他內容 -->
<!-- 使用 DownloadManager 組件 -->
<DownloadManager
:files="filesToDownload"
:dialogVisible.sync="isDialogVisible"
:zipName="zipFileName"
/>
<!-- 觸發(fā)下載對話框顯示的按鈕 -->
<el-button @click="openDownloadDialog">Download Files</el-button>
</div>
</template>
<script>
import DownloadManager from './components/DownloadManager.vue' // 根據實際路徑調整
export default {
components: {
DownloadManager
},
data () {
return {
filesToDownload: [
{ name: 'file1.txt', url: 'https://example.com/file1.txt' },
{ name: 'file2.txt', url: 'https://example.com/file2.txt' }
],
isDialogVisible: false,
zipFileName: 'downloaded_files'
}
},
methods: {
openDownloadDialog() {
this.isDialogVisible = true
}
}
}
</script>9.2 組件參數以及解釋
files: 傳遞一個文件數組,每個文件對象應包含name和url屬性,用于下載文件。dialogVisible: 控制el-dialog的可見性,使用.sync修飾符讓父組件與子組件之間雙向綁定。zipName: 傳遞生成的 ZIP 文件名。
使用 DownloadManager 組件時,通過綁定屬性 (:files, :dialogVisible.sync, :zipName) 來控制組件行為。
調用 openDownloadDialog 方法顯示下載對話框,并開始下載文件。
總結
通過本文,我們學習了如何使用 Vue 創(chuàng)建一個帶有進度顯示和打包功能的文件下載組件。我們探討了如何導入必要的包,構建組件的基礎結構,實現文件下載與進度顯示,以及如何將文件打包為 ZIP 格式供用戶下載。這種組件不僅能提升用戶體驗,還能被復用于各種場景,為我們的項目增色不少。
我們可以根據具體需求進一步擴展這個組件,比如添加錯誤處理、取消下載等功能。
到此這篇關于Vue+ElementUI創(chuàng)建一個帶有進度顯示的文件下載和打包組件功能的文章就介紹到這了,更多相關Vue ElementUI文件下載進度內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
vue3+vite加載本地js/json文件不能使用require淺析
這篇文章主要給大家介紹了關于vue3+vite加載本地js/json文件不能使用require的相關資料,require 是屬于 Webpack 的方法,在v3+vite的項目里面并不適用,需要的朋友可以參考下2023-07-07
Vue全局使用less樣式,組件使用全局樣式文件中定義的變量操作
這篇文章主要介紹了Vue全局使用less樣式,組件使用全局樣式文件中定義的變量操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-10-10

