vue实现文件批量上传及进度条展示

2023-11-12

主要实现功能

 

1.多文件拖拽上传

2.显示文件上传进度条

3.上传期间,还可以继续拖拽上传

4.可以支持手动修改上传并发任务数

5.上传失败自动重试,最大重试次数3次

6.上传过程中可以手动取消上传

 本次使用的是element ui ,上传拖拽是通过el-upload实现的。

<el-upload
  :before-upload="beforeUpload"
  action="#"
  class="upload"
  drag
  multiple
>
<el-icon class="el-icon--upload">
  <upload-filled/>
</el-icon>
<div class="el-upload__text">
  拖拽或 <em>点击上传</em>
</div>
<template #tip>
  <div class="el-upload__tip">
	请上传文件,仅支持上传文件,不支持文件夹
  </div>
</template>
</el-upload>

 上传之前,触发 beforeUpload 方法,该方法进行封装调用 

beforeUpload(raw) {
  addUploadFile(raw)
  return false
}

上传初始化逻辑

 初始化进度条等相关数据

export function addUploadFile(raw) {
    const upload = uploadStore()
    const uploadProgress = {
        progress: 0,
        file_id: '',
        file_name: raw.name,
        percent: [],
        speed: '0 MB',
        file_size: raw.size,
        upload_size: 0,
        upload_time: new Date()
    }
    // status上传状态 0 队列,1 上传中,2 上传成功 , 3 取消上传
    // failTryCount 失败上传次数, 没上传一次,自动减去已,当为0的时候,停止上传
    upload.multiFileList.push({file: raw, progress: uploadProgress, status: 0, failTryCount: 3})
    multiUpload()
}

该代码引用了一个类似vuex的存储库 Pinia

 下面内容通过pinia定义了一个存储,存储有三个字段

uploadStore()

export const uploadStore = defineStore('upload', {
    state: () => ({
        multiFileList: [],
        processNumber: 3,
        promise: []
    })
})

multiUpload()

 文件上传核心内容就是该方法了,主要时过滤上传状态为0,然后批量加入上传队列

export function multiUpload() {
    const upload = uploadStore()
    const readFileList = []
    upload.multiFileList.forEach(res => {
        if (res.status === 0) {
            readFileList.push(res)
        }
    })
    if (readFileList.length > 0) {
        multiRun(upload, readFileList.slice(0, upload.processNumber), uploadAsync)
    }
}

 multiRun()

该方法,就是并发上传核心逻辑,通过Promise进行批量上传 

function multiRun(upload, keyList, func) {
    const processNumber = upload.processNumber
    const promise = upload.promise
    for (let i = 0; i < processNumber - promise.length; i++) {
        promise.push(Promise.resolve())
    }
    let reduceNumber = promise.length - processNumber
    if (reduceNumber > 0) {
        upload.promise = promise.slice(0, reduceNumber)
    }
    for (let j = 0; j < keyList.length; j += processNumber) {
        for (let i = 0; i < processNumber; i++) {
            if (i + j < keyList.length) {
                promise[(j + i) % processNumber] = promise[(j + i) % processNumber].then(() => func(keyList[i + j])).catch(({
                                                                                                                                fileInfo,
                                                                                                                                err
                                                                                                                            }) => {
                    if (fileInfo.status === 3) {
                        console.log(fileInfo.file.name, '取消上传')
                    } else {
                        fileInfo.status = 0
                        fileInfo.failTryCount -= 1
                        if (fileInfo.failTryCount < 1) {
                            ElMessage.error(`${fileInfo.file.name} 超过最大重试次数,停止上传`)
                        } else {
                            ElMessage.error(`${fileInfo.file.name} 上传失败,正在重试`)
                            console.log(fileInfo.file.name, err)
                            multiUpload()
                        }
                    }
                })
            }
        }
    }
}

uploadAsync(fileInfo)

上传文件逻辑,进行文件的上传,进度计算等功能。本功能是模拟上传阿里云盘操作

function uploadAsync(fileInfo) {
    const progress = fileInfo.progress
    const file = fileInfo.file
    return new Promise((resolve, reject) => {
        progress.file_name = file.name
        progress.file_size = file.size
        if (fileInfo.status === 0) {
            fileInfo.status = 1
        } else {
            return resolve()
        }
        progress.progress = 10
        getUploadSid().then(async res => {
            // ElMessage.info(fileName + ' 文件读取中')
            progress.speed = '文件读取中'
            let hash = await PreHash(file, progress)
            let fileHashInfo = {
                sid: res.data.sid,
                file_name: progress.file_name,
                file_size: progress.file_size,
                pre_hash: hash
            }
            progress.progress = 20
            checkPreHash(fileHashInfo).then(async pRes => {
                if (pRes.data.check_status === true) {
                    // 秒传逻辑
                    progress.progress = 30
                    const md5Code = pRes.data.md5_token
                    progress.speed = '文件校验中'
                    // ElMessage.info(fileInfo.file_name + ' 秒传检测中')
                    let hash = await ContentHash(file, md5Code, progress)
                    fileHashInfo.proof_code = hash.proofCode
                    fileHashInfo.content_hash = hash.conHash
                    checkContentHash(fileHashInfo).then(async cRes => {
                        if (cRes.data.check_status === true) {
                            progress.progress = 100
                            progress.upload_size = progress.file_size
                            progress.speed = '秒传成功'
                            // ElMessage.success(fileName + ' 上传成功')
                            fileInfo.status = 2
                            fileInfo.upload_time = new Date()
                            multiUpload()
                            resolve()
                        } else {
                            return await ChunkedUpload(fileInfo, fileHashInfo, cRes.data.upload_extra, cRes.data.part_info_list, () => {
                                fileInfo.status = 2
                                fileInfo.upload_time = new Date()
                                multiUpload()
                                resolve()
                            }, (err) => {
                                reject({fileInfo, err})
                            })
                        }
                    }).catch((err) => {
                        reject({fileInfo, err})
                    })
                } else {
                    return await ChunkedUpload(fileInfo, fileHashInfo, pRes.data.upload_extra, pRes.data.part_info_list, () => {
                        fileInfo.status = 2
                        fileInfo.upload_time = new Date()
                        multiUpload()
                        resolve()
                    }, (err) => {
                        reject({fileInfo, err})
                    })
                }
            }).catch((err) => {
                reject({fileInfo, err})
            })
        }).catch((err) => {
            reject({fileInfo, err})
        })
    })
}

 核心上传大概就是这些逻辑

代码源码:xshare/upload.js at main · nineaiyu/xshare · GitHub

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

vue实现文件批量上传及进度条展示 的相关文章

  • 如何测试 javascript 闭包内的函数

    这似乎是不可能的 也可能是 但我正在尝试更多的 TDD 但我总是在闭包方面碰壁 假设我有以下内容 function createSomething init function privateMethod param return init
  • Android 设备上的 PhoneGap 蓝牙插件

    我一直在尝试让 PhoneGap 工作的蓝牙插件 但我似乎不知道哪里出了问题 首先 我的测试设备是 Galaxy S3 GT 19305T 应用程序是使用PhoneGap CLI http docs phonegap com en 3 0
  • 每 3 秒重复一次动画

    我正在使用 WOW js 和 animate css 现在我正在将 CSS 运行到 Infinite 我想知道如何让我的课程运行 3 秒停止并再次开始到无限 My html img src images fork png class for
  • 不和谐机器人 |不和谐.js |类型错误:无法读取未定义的属性“长度”

    我正在制作一个 Discord 机器人 并且正在使用 CodeLyon 的视频作为参考 该错误位于我的 message js 文件中 该文件包含以下内容 require dotenv config create cooldowns map
  • 如何重定向到 instagram://user?username={username}

    我的 html 页面上有这个链接 可以在特定用户上打开 Instagram 应用程序 a href Link to Instagram Profile a 我一直在寻找自动运行 url instagram user username USE
  • 如何重置使用 JavaScript 更改的 CSS 属性?

    我的导航按钮的宽度从 100px 增加到 150px 当鼠标悬停在 nav li hover width 150px 但是使用 javascript 我已经做到了 无论选择哪个选项 宽度都将继续为 150px 当选择每个选项时 它会使其他选
  • jQuery AJAX 调用 Java 方法

    使用 jQuery AJAX 我们可以调用特定的 JAVA 方法 例如从 Action 类 该 Java 方法返回的数据将用于填充一些 HTML 代码 请告诉我是否可以使用 jQuery 轻松完成此操作 就像在 DWR 中一样 此外 对于
  • 使用 jQuery/JS 打开时使
    标签的内容具有动画效果

    我只想要 HTML5 的内容details标记为 滑行 动画打开 而不是仅仅弹出打开 立即出现 这可以用 jQuery Javascript 实现吗 Fiddle http jsfiddle net 9h4Hq HTML
  • Meteor:应用程序无法在 0.9.1.1 版本上运行

    出现类似错误 Error TypeError undefined is not a function evaluating Template create anonymous function iron dynamic template j
  • Javascript正则表达式用于字母字符和空格? [关闭]

    这个问题不太可能对任何未来的访客有帮助 它只与一个较小的地理区域 一个特定的时间点或一个非常狭窄的情况相关 通常不适用于全世界的互联网受众 为了帮助使这个问题更广泛地适用 访问帮助中心 help reopen questions 我需要一个
  • 为什么是 javascript:history.go(-1);无法在移动设备上工作?

    首先 一些背景 我有一个向用户呈现搜索页面 html 表单 的应用程序 填写标准并单击 搜索 按钮后 结果将显示在标准部分下方 在结果列表中 您可以通过单击将您带到新页面的链接来查看单个结果的详细信息 在详细信息页面中 我添加了一个 返回结
  • 跟踪用户何时点击浏览器上的后退按钮

    是否可以检测用户何时单击浏览器的后退按钮 我有一个 Ajax 应用程序 如果我可以检测到用户何时单击后退按钮 我可以显示适当的数据 任何使用 PHP JavaScript 的解决方案都是优选的 任何语言的解决方案都可以 只需要我可以翻译成
  • 在javascript中解析json - 长数字被四舍五入

    我需要解析一个包含长数字的 json 在 java servlet 中生成 问题是长数字被四舍五入 当执行这段代码时 var s x 6855337641038665531 var obj JSON parse s alert obj x
  • 通过 CDN 使用 Dojo 时如何加载自定义 AMD 模块?

    我正在使用 google 的 CDN 并尝试使用他们的加载程序加载我自己的 AMD 模块 我知道我做错了什么 但我被困住了 有任何想法吗
  • Firefox 书签探索未超过 Javascript 的第一级

    我已经编写了一些代码来探索我的 Firefox 书签 但我只获得了第一级书签 即我没有获得文件夹中的链接 e g 搜索引擎 雅虎网站 谷歌网站 在此示例中 我只能访问 Search engines 和 google com 不能访问 yah
  • Laravel 中只向登录用户显示按钮

    如果我以 John 身份登录 如何才能只显示 John 的红色按钮而不显示 Susan 的红色按钮 测试系统环境 Win10 Laravel5 4 Mysql5 7 19 table class table table responsive
  • 如何在类似控制台的环境中运行 JavaScript?

    我正在尝试遵循这里的示例 http eloquentjavascript net chapter2 html http eloquentjavascript net chapter2 html and print blah 在浏览器中运行时
  • 为什么我不能在 AngularJS 中使用 data-* 作为指令的属性名称?

    On the t他的笨蛋 http plnkr co edit l3KoY3 p preview您可以注意到属性名称模式的奇怪行为data 在指令中 电话 Test of data named attribute br
  • 在 React.js 中编辑丰富的数据结构

    我正在尝试为数据结构创建一个简单的基于网格的编辑器 但我在使用 React js 时遇到了一些概念问题 他们的文档对此没有太大帮助 所以我希望这里有人可以提供帮助 首先 将状态从外部组件传输到内部组件的正确方法是什么 是否有可能将内部组件中
  • 导致回发到与弹出窗口不同的页面

    我有一个主页和一个详细信息页面 详细信息页面是从主页调用的 JavaScript 弹出窗口 当单击详细信息页面上的 保存 按钮时 我希望主页 刷新 是否有一种方法可以调用主页的回发 同时还可以从详细信息页面维护保存回发 Edit 使用win

随机推荐

  • Python当中reverse()函数

    Hello大家好 今天我想和大家分享一下Python当中的reverse 函数 reverse 函数顾名思义就是反转的意思 但是我们要注意反转的内容只能是python当中的列表 千万不要忘记了 例子如下 arr 1 2 3 4 5 6 ar
  • js数据类型之对象object类型(数组与自定义对象)

    对象object 数组与自定义对象 JavaScript 中的所有事物都是对象 字符串 数值 数组 函数 此外 JavaScript 允许自定义对象 JavaScript 提供多个内建对象 比如 String Date Array 等等 对
  • CoordinatorLayout+AppBarLayout+CollapsingToolbarLayout+Toolbar实现渐变透明的状态栏

    在之前的一篇博文里面我已经说明了CoordinatorLayout使用过程中遇到的问题 之后又发现结合CollapsingToolbarLayout使用时的另一个问题 CollapsingToolbarLayout里面的ImageView为
  • [架构之路-208]- 人人都是产品经理 - 什么是产品经理?产品经理具体是做什么的?

    目录 一 什么是产品经理 产品经理具体做什么 二 产品经理的岗位职责 三 产品经理的职业规划 一 什么是产品经理 产品经理具体做什么 在外行人看来 产品经理常常被误认为是 经理 其实产品经理只是一个岗位名称 并不是真正意义上的 经理 或者说
  • 深入浅出UML类图(五)

    实例分析3 售票机控制程序 某运输公司决定为新的售票机开发车票销售的控制软件 图I给出了售票机的面板示意图以及相关的控制部件 图I 售票机面板示意图 售票机相关部件的作用如下所述 1 目的地键盘用来输入行程目的地的代码 例如 200表示总站
  • python的几个重要基本概念

    1 整数 小数 布尔值和空值 整数 int类型 计算机中整数是有最大值的 与计算机的存储能力有关 即使是这样计算机中的整数值也是很大很大的 这一点基本上不需要担心的 小数 也称 浮点数 float类型 小数就是带小数点的数包括 1 0 等等
  • sqlite数据库-------清除数据,数据库文件大小不变解决方法

    现象 删除表格的全部数据 DELETE FROM Name 原因 当在sqlite中删除了大量数据后 数据库文件的大小还是那样 没有变 原因是 从Sqlite删除数据后 未使用的磁盘空间被添加到一个内在的 空闲列表 中用于存储你下次插入的数
  • IP协议号与传输层端口

    网络层 数据包的包格式里面有个很重要的字段叫做协议号 比如在传输层如果是tcp连接 那么在网络层ip包里面的协议号就将会有个值是6 如果是udp的话那个值就是17 传输层 传输层 通过接口关联 端口的字段叫做端口 应用层 协议号是存在于IP
  • 设计模式:桥接模式(c++实现案例)

    桥接模式 桥接模式是一种结构型设计模式 可将业务逻辑或一个大类拆分为不同的层次结构 从而能独立地进行开发 桥接模式通过将继承改为组合的方式来解决这个问题 具体来说 就是抽取其中一个维度并使之成为独立的类层次 这样就可以在初始类中引用这个新层
  • 2016年蓝桥杯省赛C/C++ A组-寒假作业

    题目 现在小学的数学题目也不是那么好玩的 看看这个寒假作业 每个方块代表1 13中的某一个数字 但不能重复 比如 6 7 13 9 8 1 3 4 12 10 2 5 以及 7 6 13 9 8 1 3 4 12 10 2 5 就算两种解法
  • ug产品摆正高级技巧_UG NX如何摆正产品零件模型

    原标题 UG NX如何摆正产品零件模型 有时 我们拿到一个产品模型 按F8也是一个歪的视图 如图 那么该如何才能将产品摆正呢 其实很简单 我们只需要移动下就好了 按ctrl t移动对象 选中模型 变化选项里面运动选择从csys到csys 指
  • 数据结构——串——王道

    目录 串 定义 串和线性表的联系及不同 串的基本操作 存储结构 顺序存储 链式存储 基本操作的实现 字符串模式匹配算法 朴素模式匹配算法 KMP算法 串 定义 串 即字符串 String 是由零个或多个字符组成的有限序列 一般记为 其中 S
  • 编写cuda代码查看自己机器的显卡信息

    代码如下 cudaDeviceProp 是一个结构体 一些参数就是cudaDeviceProp 结构体中的参数 cudaGetDeviceProperties cudade 0 这个函数就是实例化 第一个参数就是实例化 第二个参数是哪一个显
  • Windows如何开启虚拟化,以安装虚拟机?

    参考 Windows如何开启虚拟化 以安装虚拟机 作者 一只青木呀 发布时间 2020 08 28 20 58 45 网址 https blog csdn net weixin 45309916 article details 108286
  • STM32Cube 中的STM32例程EXAMPLE

    STM32 Cube 其实包含的大量的程序例子 一些模块程序编写不需要再去找其他例子 在这就能找到 在这里插入图片描述 https img blog csdnimg cn 7862d4aba5b54d4da2db87586b4ae859 p
  • Spring源码--Bean的加载

    bean的加载在AbstractBeanFactory的doGetBean中 protected
  • Allegro怎么进行走线

    1 切换到走线模式 点击走线 在options中进行走线参数设置 如下图
  • 2022蓝桥杯省赛——顺子日期

    问题描述 本题为填空题 只需要算出结果后 在代码中使用输出语句将所填结果输出即可 小明特别喜欢顺子 顺子指的就是连续的三个数字 123 456 等 顺子日期指的就是在日期的 yyyymmdd 表示法中 存在任意连续的三位数是一个顺子的日期
  • 并行CRC—Verilog代码实现

    CRC并行Verilog 1 构造系数方阵F 2 计算CRC系数 3 计算DATA系数 3 1 DATA系数真相 4 合并系数 5 验证 6 其他选项 6 1输入翻转 6 2预设初值 6 3输出翻转 取反 7 Matlab生成并行crc代码
  • vue实现文件批量上传及进度条展示

    主要实现功能 1 多文件拖拽上传 2 显示文件上传进度条 3 上传期间 还可以继续拖拽上传 4 可以支持手动修改上传并发任务数 5 上传失败自动重试 最大重试次数3次 6 上传过程中可以手动取消上传 本次使用的是element ui 上传拖