集成单文件、多文件下载、监控下载进度、取消下载的一个类

本文介绍了一个自定义的文件下载类,支持单文件和多文件下载,利用JSZip处理多文件压缩,提供下载进度回调和取消下载功能,简化开发者操作。
摘要由CSDN通过智能技术生成

封装一个文件下载的类

这里自己封装了一个关于文件下载的类。开发者只需要通过实例一个下载对象,就可以进行单文件、多文件下载,并且可以监控文件下载进度,以及进行下载取消

1.前期准备

因为涉及到多文件下载,这里需要基于jszip插件。可在文章顶部点击下载并在代码中引入。

2.代码

// 下载各类型文件
export class FileDownLoad {
    constructor(path, process) {
        if (Array.isArray(path)) {
            if (path.length > 1) {
                this.isMult = true
                this.path = path
            } else {
                this.path = path[0]
                this.isMult = false
            }
        } else {
            this.path = path;
            this.isMult = false
        }

        this.controller = new AbortController();
        this.getProcess = process
    }

    //下载文件
    downloadPaper() {
        if (this.isMult) {
            this.downloadMult()
        } else {
            this.downloadSingle()
        }
    }

    //多文件压缩zip后下载 需引入多文件压缩插件
    async downloadMult() {
        const zip = new JSZip();
        const {
            signal
        } = this.controller;
        for (let i = 0; i < this.path.length; i++) {
            // 获取文件名称
            let fileName = this.getFileName(this.path[i]);
            let fileType = this.getFileType(this.path[i]);
            try {
                const response = await fetch(this.path[i], {
                    method: "get",
                    mode: "cors",
                    signal
                })

                //设置下载进度
                const data = await this.setProcess(response, fileName);

                zip.file(fileName, new Blob(data, {
                    type: fileType == "pdf" ? "application/pdf" : fileType == "word" ?
                        "application/msword" : fileType == "excel" ? "application/vnd.ms-excel" : ""
                }));
            } catch (error) {
                //是否是用户中止下载操作
              if (error.name === 'AbortError') {
                console.error('中止下载')
            } else {
                console.error('下载出错了')
            }
            }
        }

        zip.generateAsync({
            type: "blob"
        }).then((content) => {
            let url = window.URL.createObjectURL(content);

            const link = document.createElement("a");
            link.href = url;
            link.setAttribute("download", this.getFileName(this.path[0]) + '等文件.zip');
            document.body.appendChild(link);
            link.click();
            link.remove();
        });
    }



    //单个文件下载
    downloadSingle() {
        // 获取文件类型
        let type = this.getFileType(this.path);
        // 获取文件名称
        let fileName = this.getFileName(this.path);
        if (type == 'img') {
            this.downloadImg(this.path).then((res) => {
                // 创建标签
                const link = document.createElement("a");
                link.href = res;
                // a 标签设置 download 属性,直接下载图片
                link.setAttribute("download", fileName + '.png');
                document.body.appendChild(link);
                link.click();
                link.remove();
            }).catch((err) => {
                console.log(err);
            })
        } else {
            this.downloadFile({
                url: this.path,
                type: type,
                name: fileName
            })
        }
    }
    getFileType(url) {
        if (url) {
            // 先用斜杠截取
            let tempArr1 = url.split('/');
            // 获取到截取结果的最后一位,即文件名称
            let fileName = tempArr1[tempArr1.length - 1];
            // 再用点截取
            let tempArr2 = fileName.split('.');
            // 得到文件类型
            let type = tempArr2.at(-1);
            let myType = ''
            if (type == 'jpg' || type == 'jpeg' || type == 'png') {
                myType = 'img'
            } else if (type == 'pdf') {
                myType = 'pdf'
            } else if (type == 'doc' || type == 'doxc') {
                myType = 'word'
            } else if (type == 'xlsx' || type == 'xls') {
                myType = 'excel'
            }
            return myType;
        } else {
            return '';
        }
    }
    getFileName(url) {
        if (url) {
            // 先用斜杠截取
            let tempArr1 = url.split('/');
            // 获取到截取结果的最后一位,即文件名称
            let fileName = tempArr1[tempArr1.length - 1];
            return fileName;
        } else {
            return '';
        }
    }
    downloadImg(url) {
        return new Promise((resolve, reject) => {
            // 重绘图片
            let image = new Image();
            image.onload = function () {
                let canvas = document.createElement('canvas');
                canvas.width = this.naturalWidth;
                canvas.height = this.naturalHeight;
                canvas.getContext('2d').drawImage(image, 0, 0);
                let result = canvas.toDataURL('image/png')
                resolve(result);
            };
            // 跨域获取当前图片
            image.setAttribute("crossOrigin", 'Anonymous');
            image.src = url
            image.onerror = () => {
                reject(new Error('urlToBase64 error'));
            };
        })
    }

    setProcess(response, name) {
        try {
            return new Promise(async resolve => {
                const reader = response.body.getReader();
                const contentLength = +response.headers.get('Content-Length');
                let receiveLength = 0;
                let chunks = [];
                while (true) {
                    const {
                        done,
                        value
                    } = await reader.read();
                    if (done) {
                        break
                    }
                    chunks.push(value);
                    receiveLength += value.length;
                    this.getProcess(receiveLength, contentLength, name)
                }
                resolve(chunks)
            })
        } catch (error) {
            if (error.name === 'AbortError') {
                console.error('中止下载')
            } else {
                console.error('下载出错了')
            }
        }

    }
    downloadFile(data) {
        const {
            signal
        } = this.controller;
        try {
            fetch(data.url, {
                method: "get",
                mode: "cors",
                signal
            })
                .then((response) => {
                    //下载进度设置
                    this.setProcess(response, data.name).then((res) => {
                        const downloadUrl = window.URL.createObjectURL(
                            //new Blob() 对后端返回文件流类型处理
                            new Blob(res, {
                                type: data.type == "pdf" ? "application/pdf" : data.type == "word" ?
                                    "application/msword" : data.type == "excel" ? "application/vnd.ms-excel" : ""
                            })
                        );
                        //word文档为msword,pdf文档为pdf
                        const link = document.createElement("a");
                        link.href = downloadUrl;
                        link.setAttribute("download", data.name);
                        document.body.appendChild(link);
                        link.click();
                        link.remove();
                    })
                })

        } catch (error) {
            if (error.name === 'AbortError') {
                console.error('中止下载')
            } else {
                console.error('下载出错了')
            }
        }

    }
}

3.使用

通过new FileDownLoad实例一个对象fileDownLoad

paths:可直接访问的文件地址,字符串或数组类型。代码会判断:单个文件时触发单文件下载;多个文件时会生成一个压缩包并下载。

getProcess:文件下载进度的回调,返回当前接收数据量、总数据量、文件名称;可以通过这些参数进行下载进度的展示。

fileDownLoad = new FileDownLoad(paths, getProcess);
fileDownLoad.downloadPaper();
//获取下载进度
const getProcess = function (receive, total, name) {
  fileProcessShow.value = receive !== total;
  filePercent.value = ((receive / total) * 100).toFixed(0);
  fileTotal.value = (total / (1024 * 1024)).toFixed(2) + "M";
  fileName.value = name;
};

4.取消下载

调用实例对象 fileDownLoad.controller.abort 方法取消下载。

const stopDownloadClick = function () {
  fileDownLoad.controller.abort();
  fileDownLoad = null;
  fileProcessShow.value = false;
  fileTotal.value = 0;
  filePercent.value = 0;
};
  • 10
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值