Vue+ElementUI技巧分享:创建一个带有进度显示的文件下载和打包组件

在现代前端开发中,用户体验至关重要,尤其是在处理文件下载时。为用户提供实时的下载进度显示和打包功能,不仅能提升用户体验,还能使应用更具专业性。在本文中,我们将创建一个 Vue 组件,用于显示文件下载进度,并将下载的文件打包成 ZIP 供用户下载。

文章目录

  • 前言
  • 1. 组件功能概述
  • 2. 导入所需的包
  • 3. 构建基础组件
  • 4.实现文件下载与进度显示
  • 5. 打包文件为 ZIP
  • 6. 控制对话框的显示与隐藏
  • 7. 可能会遇到的问题:处理跨域请求 (CORS)
    • 7.1 什么是 CORS?
    • 7.2 常见的 CORS 错误
    • 7.3 解决 CORS 问题的方法
    • 7.4 说明
  • 8. 完整源代码
  • 9. 组件调用
    • 9.1 引入并注册组件
    • 9.2 组件参数以及解释
  • 总结


前言

在应用中处理多个文件的下载时,用户希望看到清晰的进度显示,同时在下载多个文件时,将它们打包成 ZIP 文件提供下载也是常见需求。通过使用 Vue 和一些实用的 JavaScript 库,我们可以轻松实现这一功能。


1. 组件功能概述

我们要实现的 Vue 组件具备以下功能:

  • 下载多个文件,并实时显示每个文件的下载进度。
  • 打包下载的文件为 ZIP 并显示打包进度。
  • 在进度条内同时显示文件名称和下载百分比。
  • 下载完成后自动关闭对话框。
    导入进度展示

2. 导入所需的包

在开始构建组件之前,我们需要先导入一些关键的 JavaScript 库。这些库将帮助我们实现文件下载、ZIP 打包和文件保存功能。

npm install axios jszip file-saver --save
  • axios: 用于执行 HTTP 请求,并获取文件数据。
  • jszip: 用于在前端生成 ZIP 文件。
  • file-saver: 用于触发浏览器下载功能,保存生成的 ZIP 文件。

在 Vue 组件中,我们可以通过以下方式导入这些库:

import axios from 'axios'
import JSZip from 'jszip'
import { saveAs } from 'file-saver'

3. 构建基础组件

我们从构建基础的 Vue 组件结构开始,该组件将接收文件列表和控制对话框的显示状态。

<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 来触发浏览器下载。

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 并触发下载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 监听 dialogVisible 的变化。当对话框打开时,我们启动下载流程,并在所有操作完成后关闭对话框。

watch: {dialogVisible (newVal) {this.internalDialogVisible = newValif (newVal) {this.downloadFiles = this.files.map(file => ({ ...file, progress: 0 }))this.packProgress = 0this.startDownload()}},internalDialogVisible (newVal) {this.$emit('update:dialogVisible', newVal)}
}

7. 可能会遇到的问题:处理跨域请求 (CORS)

在实现文件下载功能时,尤其是当我们从不同的域名或服务器请求文件资源时,可能会遇到跨域资源共享 (CORS) 问题。CORS 是一种浏览器安全机制,用于防止恶意网站在用户不知情的情况下发起跨域请求。因此,当我们的 Vue 应用从与其源不同的服务器请求资源时,浏览器会根据 CORS 规则来决定是否允许该请求。

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 问题的方法

  1. 服务器端配置

    • 在理想情况下,我们应当拥有对目标服务器的控制权,并在服务器端配置允许的跨域请求。具体方法是在服务器的响应头中添加 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 设置为特定的域名,以限制允许跨域访问的来源。
  2. 使用代理服务器

    • 如果我们无法控制目标服务器的配置,可以考虑在开发环境中使用代理服务器。通过 Vue CLI 我们可以轻松配置代理,将请求通过代理服务器发送,从而避免 CORS 问题。以下是 Vue CLI 中的 vue.config.js 配置示例:
      module.exports = {devServer: {proxy: {'/api': {target: 'https://example.com',changeOrigin: true,pathRewrite: { '^/api': '' }}}}
      }
      
      通过这种配置,所有发往 /api 的请求都会被代理到 https://example.com,从而避免直接跨域请求导致的 CORS 问题。
  3. 使用 JSONP

    • JSONP (JSON with Padding) 是一种传统的跨域解决方案,主要用于 GET 请求。然而,由于它仅支持 GET 请求且具有安全风险,现代应用中较少使用。
  4. 启用 CORS 插件

    • 在开发环境中,为了临时解决 CORS 问题,可以使用浏览器插件如 CORS Unblock。不过,这只适用于开发和调试阶段,不推荐在生产环境中使用。

7.4 说明

CORS 问题是开发跨域资源请求时不可避免的挑战之一。在实现文件下载功能时,务必确保服务器配置正确的 CORS 头,以允许来自我们应用的请求。如果无法控制服务器配置,可以考虑使用代理服务器或其他临时解决方案。在生产环境中,最好的做法是从服务器端正确处理 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 并触发下载,同时更新打包进度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 = newValif (newVal) {this.downloadFiles = this.files.map(file => ({ ...file, progress: 0 }))this.packProgress = 0this.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"/><!-- 触发下载对话框显示的按钮 --><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: 传递一个文件数组,每个文件对象应包含 nameurl 属性,用于下载文件。
  • dialogVisible: 控制 el-dialog 的可见性,使用 .sync 修饰符让父组件与子组件之间双向绑定。
  • zipName: 传递生成的 ZIP 文件名。

使用 DownloadManager 组件时,通过绑定属性 (:files, :dialogVisible.sync, :zipName) 来控制组件行为。
调用 openDownloadDialog 方法显示下载对话框,并开始下载文件。


总结

通过本文,我们学习了如何使用 Vue 创建一个带有进度显示和打包功能的文件下载组件。我们探讨了如何导入必要的包,构建组件的基础结构,实现文件下载与进度显示,以及如何将文件打包为 ZIP 格式供用户下载。这种组件不仅能提升用户体验,还能被复用于各种场景,为我们的项目增色不少。

我们可以根据具体需求进一步扩展这个组件,比如添加错误处理、取消下载等功能。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/403188.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

与人打交道的七个绝招

与人打交道的七个绝招&#xff0c;学会了让你混得风生水起&#xff01; 一、跟强者打交道&#xff0c;别绕圈子。就事论事&#xff0c;直奔主题&#xff1b; 二、跟没钱的人打交道&#xff0c;就直接告诉他能挣多少钱&#xff1b; 三、跟小人打交道&#xff0c;越虚假越好&…

URP平面阴影合批处理 shadow

闲谈 相信大家在日常工作中发现了一个问题 &#xff0c; urp下虽然可以做到3个Pass 去写我们想要的效果&#xff0c;但是&#xff0c;不能合批&#xff08;不能合批&#xff0c;那不是我们CPU要干冒烟~&#xff01;&#xff09; 好家伙&#xff0c;熊猫老师的偏方来了 &#x…

JavaScript基础(33)_鼠标滚轮滚动事件、键盘事件

鼠标滚轮滚动事件&#xff1a;onwheel 获取鼠标滚轮滚动的方向&#xff1a;wheelDelta 比如&#xff1a;向上滚动&#xff1a;109 &#xff08;所有正值都是向上&#xff09; 向下滚动&#xff1a;-109&#xff08;所有负值都是向下&#xff09; 注意&#xff1a;当…

基于华为atlas下的yolov5+BoT-SORT/ByteTrack煤矿箕斗状态识别大探索

写在前面&#xff1a; 本项目的代码原型基于yolov5yolov8。其中检测模型使用的yolov5&#xff0c;跟踪模型使用的yolov8。 这里说明以下&#xff0c;为什么不整体都选择yolov8呢&#xff0c;v8无疑是比v5优秀的&#xff0c;但是atlas这块经过不断尝试没有过去&#xff0c;所以…

AWS boto3 脚本访问 AWS 资源

AWS boto3 脚本访问 AWS 资源 引言boto3主要功能常见用例安装和基本使用 boto3.Client() 低级客户端基本用法关键参数 boto3.resource() 高级客户端常见参数用法 boto3.resource VS boto3.client相似点不同点总结 关于身份验证凭证隐式身份凭证显式身份验证凭证assuem role如何…

出海笔记精华问答 | 第四期

更新出海问答第四期&#xff0c;希望可以继续帮助大家解决问题哈。 Q1:当stripe把资金全退给客户但是货又发了&#xff0c;这是什么情况&#xff1f; A1: 这种情况一般是stripe不跟你合作了或者发生了争议。 Q2:如何知道stripe回复你的邮件是人工回复还是机器人回复&#xff…

Linux基础入门---安装vmware

&#x1f600;前言 本篇博文是关于Linux基础入门和vmwarel5.5下载&#xff0c;希望你能够喜欢。 &#x1f3e0;个人主页&#xff1a;晨犀主页 &#x1f9d1;个人简介&#xff1a;大家好&#xff0c;我是晨犀&#xff0c;希望我的文章可以帮助到大家&#xff0c;您的满意是我的动…

Merkle树(Merkle Tree):高效地验证某个数据块是否包含在数据集中

目录 Merkle树(Merkle Tree) 一、基本结构 二、构建过程 三、主要作用 四、应用领域 Merkle树(Merkle Tree) Merkle树(Merkle Tree),也被称为默克尔树或Merkle哈希树,是一种基于哈希的数据结构,主要用于验证大规模数据集的完整性和一致性。它的名字来源于其发明…

大数据技术——实战项目:广告数仓(第七部分)数仓工作流调度实操

目录 第12章 广告数仓全流程调度 12.2 新数据生成 12.2.1 广告监测日志 12.2.2 广告管理平台数据 12.3 工作流调度实操 12.3.1 DolphinScheduler集群模式 12.3.2 DolphinScheduler单机模式 第12章 广告数仓全流程调度 12.1 调度工具Dolphinscheduler DolphinScheduler…

VirtualBox上的Oracle Linux虚拟机安装Docker全流程

1.安装docker依赖 yum install -y yum-utils device-mapper-persistent-data lvm2 2.安装docker仓库 yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo 生成docker的yum源配置到在 /etc/yum.repos.d/docker-ce.repo 3.安装D…

Linux内核分析(调度类和调度实体)

文章目录 前言一、调度类1. stop_sched_class2. dl_sched_class3. rt_sched_class4. fair_sched_class5. idle_sched_class总结 二、调度类中的操作函数三、调度实体 前言 调度是操作系统内核的一个关键职责&#xff0c;它涉及到如何合理分配CPU时间给不同的进程或线程。在Lin…

uniapp打包H5的时候 清楚缓存(不安装依赖的前提下)

问题 在写项目的时候&#xff0c;打包好一个H5 发布成功&#xff0c;后来又重新打包新的包进行更新迭代&#xff0c;但是用户手机上还是上一个版本&#xff0c;本地缓存还是没有清除。 解决问题 步骤一&#xff1a;html不缓存 在html中&#xff0c;解决缓存的方法主要是依赖…

Keepalived学习

环境准备&#xff1a;两台服务器&#xff0c;两台客户机&#xff0c;关闭火墙和selinux 在两台主机上安装ka yum install keepalived -y 开启软件 keepalived配置 进入文件 vim /etc/keepalived/keepalived.conf 修改配置 配置slave 效果 在另一台路由配置 抢占模式和非…

简洁清新个人博客网页模板演示学习

30多款个人博客、个人网站、个人主页divcss,html在线预览,个人静态页面模板(wordpress、帝国cms、typecho主题模板).这些简洁和优雅的博客网页模板,为那些想成为创建博客的个人或媒体提供灵感设计。网页模板可以记录旅游、生活方式、食品或摄影博客等网站。部分网页模板来源网友…

二叉树进阶之二叉搜索树:一切的根源

前言&#xff1a; 在学完了简单的容器与C面向对象的三大特性之后&#xff0c;我们首先接触的就是map与set两大容器&#xff0c;但是这两个容器底层实现的原理是什么呢&#xff1f;我们不而知&#xff0c;今天&#xff0c;主要来为学习map与set的底层原理而打好基础&#xff0c…

面试官:Java虚拟机是什么,Java虚拟机的内存模型是什么样子的?

哈喽&#xff01;大家好&#xff0c;我是小奇&#xff0c;一个专给面试官添堵的撑序员 小奇打算以轻松幽默的对话方式来分享一些技术&#xff0c;如果你觉得通过小奇的文章学到了东西&#xff0c;那就给小奇一个赞吧 文章持续更新&#xff0c;可以微信搜索【小奇JAVA面试】第一…

基于WEB的旅游推荐系统设计与实现

TOC springboot280基于WEB的旅游推荐系统设计与实现 第1章 绪论 1.1选题动因 当前的网络技术&#xff0c;软件技术等都具备成熟的理论基础&#xff0c;市场上也出现各种技术开发的软件&#xff0c;这些软件都被用于各个领域&#xff0c;包括生活和工作的领域。随着电脑和笔…

SVN权限控制解析

一、基础数据说明 1. 代码目录存在多级 图1-1 SVN目录 如图1-1&#xff1a; 第一级目录是 科顺&#xff0c;代表 科顺项目&#xff0c;项目文件包括 文档、代码等等。第二级目录 分别是 2.1 resources 用于存放文档&#xff0c;开发和实施均需…

Qt登录窗口

#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget),btn(new QPushButton("取消", this)),login_btn(new QPushButton("登录", this)) { ui->setupUi(this);thi…

Llama 3.1深度解析:405B、70B及8B模型的多语言与长上下文处理能力

Llama 3.1 发布了&#xff01;今天我们迎来了 Llama 家族的新成员 Llama 3.1 进入 Hugging Face 平台。我们很高兴与 Meta 合作&#xff0c;确保在 Hugging Face 生态系统中实现最佳集成。Hub 上现有八个开源权重模型 (3 个基础模型和 5 个微调模型)。 Llama 3.1 有三种规格: …