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

 更新时间:2022年12月24日 08:34:06   作者:第九系艾文  
开发项目的时候,用到文件上传的功能很常见,包括单文件上传和多文件上传,下面这篇文章主要给大家介绍了关于vue文件批量上传及进度条展示的实现方法,需要的朋友可以参考下

主要实现功能

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

总结

到此这篇关于vue文件批量上传及进度条展示实现的文章就介绍到这了,更多相关vue文件批量上传及进度条内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • vue代码分割的实现(codesplit)

    vue代码分割的实现(codesplit)

    这篇文章主要介绍了vue代码分割的实现(codesplit),做了代码分割后,会将代码分离到不同的bundle中,然后进行按需加载这些文件,需要的朋友可以参考下
    2018-11-11
  • Vue项目中常用的工具函数总结

    Vue项目中常用的工具函数总结

    这篇文章主要给大家介绍了关于Vue项目中常用的工具函数,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2021-09-09
  • 使用electron打包Vue前端项目的详细流程

    使用electron打包Vue前端项目的详细流程

    这篇文章主要介绍了使用electron打包Vue前端项目的详细流程,文中通过图文结合的方式给大家介绍的非常详细,对大家学习electron打包Vue有一定的帮助,需要的朋友可以参考下
    2024-04-04
  • 教你使用vue3写Json-Preview的示例代码

    教你使用vue3写Json-Preview的示例代码

    这篇文章主要介绍了用vue3写了一个Json-Preview的相关知识,引入后直接<json-preview v-model="jsonData"></json-preview>就可以使用了,本文通过示例代码给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-06-06
  • 详解Vue3中对VDOM的改进

    详解Vue3中对VDOM的改进

    这篇文章主要介绍了详解Vue3中对VDOM的改进,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-04-04
  • 解决echart在vue中id重复问题

    解决echart在vue中id重复问题

    这篇文章主要介绍了解决echart在vue中id重复问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-03-03
  • el-table 选择框根据条件设置某项不可选中的操作代码

    el-table 选择框根据条件设置某项不可选中的操作代码

    这篇文章主要介绍了el-table 选择框根据条件设置某项不可选中的操作代码,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
    2024-03-03
  • Vue概念及常见命令介绍(1)

    Vue概念及常见命令介绍(1)

    这篇文章主要为大家详细介绍了Vue概念及常见命令,介绍了vue.js声明式渲染、双向绑定及常用指令,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-12-12
  • vue在IIS服务器部署后路由无法跳转

    vue在IIS服务器部署后路由无法跳转

    在IIS服务器上部署Vue项目时,可能会遇到路由无法正常跳转的问题,解决方法有两种,下面就来具体介绍一下解决方法,感兴趣的可以了解一下
    2024-10-10
  • Vue SSR 组件加载问题

    Vue SSR 组件加载问题

    这篇文章主要介绍了Vue SSR 组件加载问题,非常不错,具有参考借鉴价值,需要的朋友可以参考下
    2018-05-05

最新评论