首页 前端知识 vue-simple-uploader 的使用(学习笔记)

vue-simple-uploader 的使用(学习笔记)

2024-09-01 00:09:47 前端知识 前端哥 973 906 我要收藏

1.背景:  vue-simple-uploader 用于进行文件夹的上传,且项目要支持上传大文件,elementUI并不支持上传文件夹,所以使用vue-simple-uploader。

2.特点:

  • 支持文件、多文件、文件夹上传;支持拖拽文件、文件夹上传;
  • 可暂停、继续上传、分块上传;
  • 文档:https://github.com/simple-uploader/Uploader/blob/develop/README_zh-CN.md

3.vue-simple-uploader的安装: 

  1. 命令:npm install vue-simple-uploader --save
  2. 在main.js 中
    import uploader from 'vue-simple-uploader';
    Vue.use(uploader);
    
  3. 配置选项:
    options: {
            target: 'http://localhost:8080', // SpringBoot后台接收文件夹数据的接口
            simultaneousUploads: 10, // 支持同时上传数量
            autoStart: false, // 自动上传
            panelShow: false,
            allowDuplicateUploads: false, // 上传过得文件不可以再上传
            testChunks: false, // 是否分片-不分片
            chunkSize: '102400000000',//块大小
            //query参数是带有数据的post的额外参数,policy、OSSAccessKeyId和signature是获取到的后端签名返回,success_action_status需设置为 200
            query: (file) => {
              
              return {
                name: file.name,
                key: file.key,
                policy,
                OSSAccessKeyId: accessId,
                signature,
                success_action_status: 200,
              };
            },
          }
    

4.常用的方法 

  • fileAdded(file, event): 用于文件的验证,可以判断可接受的文件类型,不支持的格式会返回false,拒绝上传,添加文件时,同样也可使用浏览器的event对象;
  • filesAdded(files, fileList, event): 和.fileAdded相同,不过是用于多文件的验证;
  • fileSuccess(rootFile, file, message, chunk):完成一个特定的文件上传,rootFile是根文件夹,file是要上传的文件对象,message是服务器返回的响应信息,第四个参数' chunk '是' Uploader.Chunk '的实例;

  • complete():所有的文件都上传成功;

  • fileProgress(rootFile): 获取文件上传的进度,rootFile是所有文件;

  • fileError(rootFile, file, message, chunk):特定的文件上传失败,可在这个回调函数中给用户提示

5.使用:

        1.DOM部分

<template>
    <!-- 上传器 -->
    <uploader ref='uploader' :options='options' :autoStart=false :file-status-text='fileStatusText'
        @file-added='onFileAdded' @file-success='onFileSuccess' @file-removed="filesRemove" @file-error='onFileError'
        class='uploader-ui'>
        <uploader-unsupport></uploader-unsupport>
        <uploader-drop>
            <div>
                <uploader-btn id='global-uploader-btn' :attrs='attrs' ref='uploadBtn'>
                    选择文件
                    <i class='el-icon-upload el-icon--right'></i>
                </uploader-btn>
            </div>
        </uploader-drop>
        <uploader-list></uploader-list>
    </uploader>
</template>

        2.script部分

        

<script>

export default {
    
    data() {
        return {
            options: {
                //目标上传 URL,默认POST
                target: process.env.VUE_APP_BASE_URL + '/uploader/chunk',
                //分块大小(单位:字节)
                chunkSize: '2048000',
                //上传文件时文件内容的参数名,对应chunk里的Multipart对象名,默认对象名为file
                fileParameterName: 'upfile',
                //失败后最多自动重试上传次数
                maxChunkRetries: 3,
                changeOrigin: true,
                //是否开启服务器分片校验,对应GET类型同名的target URL
                testChunks: true,
                headers: { 'Authorization': 'Bearer ' + localStorage.getItem('token') },
                /*
                服务器分片校验函数,判断秒传及断点续传,传入的参数是Uploader.Chunk实例以及请求响应信息
                reponse码是successStatuses码时,才会进入该方法
                reponse码如果返回的是permanentErrors 中的状态码,不会进入该方法,直接进入onFileError函数 ,并显示上传失败
                reponse码是其他状态码,不会进入该方法,正常走标准上传
                checkChunkUploadedByResponse函数直接return true的话,不再调用上传接口
                */
                checkChunkUploadedByResponse: function (chunk, response_msg) {
                    let objMessage = JSON.parse(response_msg);
                    if (objMessage.skipUpload) {
                        return true;
                    }
                    return (objMessage.uploadedChunks || []).indexOf(chunk.offset + 1) >= 0;
                }
            },
            attrs: {
                accept: ACCEPT_CONFIG.getAll()
            },
            fileStatusText: {
                success: '上传成功',
                error: '上传失败',
                uploading: '上传中',
                paused: '暂停',
                waiting: '等待上传'
            }
        };
    },
    methods: {
        onFileAdded(file) {
            this.computeMD5(file);
        },
        /*
        第一个参数 rootFile 就是成功上传的文件所属的根 Uploader.File 对象,它应该包含或者等于成功上传文件;
        第二个参数 file 就是当前成功的 Uploader.File 对象本身;
        第三个参数就是 message 就是服务端响应内容,永远都是字符串;
        第四个参数 chunk 就是 Uploader.Chunk 实例,它就是该文件的最后一个块实例,如果你想得到请求响应码的话,chunk.xhr.status就是
        */
        onFileSuccess(rootFile, file, response, chunk) {
            //refProjectId为预留字段,可关联附件所属目标,例如所属档案,所属工程等
            file.refProjectId = '123456789';
            console.log('::::', file);
            let data = file
            data.filename = file.name
            data.identifier = file.uniqueIdentifier
            data.totalSize = file.size
            data.alluxioPath = this.sendContent.alluxioPath
            data.userStorageId = this.sendContent.id
            console.log('file', file, data)

            mergeFile(data).then(res => {
                console.log('23342', res)
                console.log('父组件', this.$parent)
                // if (res.code === 415) {
                //     console.log('合并操作未成功,结果码:' + res.code);
                // }
                if (res.code == 200) {
                    if (this.sendContent.idArray && this.sendContent.idArray.length > 0) {
                        this.sendContent.idArray.forEach((item) => {
                            // this.$parent.refreshList(item)
                            console.log('aaaaaaaaa',item)
                            this.$emit('refresh', item)
                            this.$emit('getFather')
                        })
                        this.$message.success(res.message)
                    }
                } else {
                    this.$message.error(res.message)
                }
            })
            // .catch(function (error) {
            //     console.log('合并后捕获的未知异常:' + error);
            // });
        },

        filesRemove(file) {
            // this.$refs.uploader.pause();
            file.paused = true
            let data = file
            data.filename = file.name
            data.identifier = file.uniqueIdentifier
            data.totalSize = file.size
            data.alluxioPath = this.sendContent.alluxioPath
            data.userStorageId = this.sendContent.id
            deleteMkFile(data).then((res) => {
                console.log('delete', res)
                if (res.code == 200) {
                    this.$message.success(res.msg)
                } else {
                    this.$message.error(res.msg)
                }
            })
            // const uploaderInstance = this.$refs.uploader.uploader;
            // let temp = uploaderInstance.fileList.findIndex(e => e.uniqueIdentifier === file.uniqueIdentifier)
            // if (temp > -1) {
            //     uploaderInstance.fileList[temp].cancel();   //这句代码是删除所选上传文件的关键
            // }
        },

        onFileError(rootFile, file, response, chunk) {
            console.log('上传完成后异常信息:' + response);
        },

        /**
         * 计算md5,实现断点续传及秒传
         * @param file
         */
        computeMD5(file) {
            file.pause();

            //单个文件的大小限制2G
            let fileSizeLimit = 2 * 1024 * 1024 * 1024;
            console.log('文件大小:' + file.size);
            console.log('限制大小:' + fileSizeLimit);
            console.log('alluxioPath' + this.sendContent.alluxioPath);
            // if (file.size > fileSizeLimit) {
            //     this.$message({
            //         showClose: true,
            //         message: '文件大小不能超过2G'
            //     });
            //     file.cancel();
            // }

            let fileReader = new FileReader();
            let time = new Date().getTime();
            let blobSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice;
            let currentChunk = 0;
            const chunkSize = 10 * 1024 * 1000;
            let chunks = Math.ceil(file.size / chunkSize);
            let spark = new SparkMD5.ArrayBuffer();
            //由于计算整个文件的Md5太慢,因此采用只计算第1块文件的md5的方式
            let chunkNumberMD5 = 1;

            loadNext();

            fileReader.onload = (e => {
                spark.append(e.target.result);

                if (currentChunk < chunkNumberMD5) {
                    loadNext();
                } else {
                    let md5 = spark.end();
                    file.uniqueIdentifier = md5;
                    file.resume();
                    console.log(`MD5计算完毕:${file.name} \nMD5:${md5} \n分片:${chunks} 大小:${file.size} 用时:${new Date().getTime() - time} ms`);
                }
            });

            fileReader.onerror = function () {
                this.error(`文件${file.name} 读取出错,请检查该文件`);
                file.cancel();
            };

            function loadNext() {
                let start = currentChunk * chunkSize;
                let end = ((start + chunkSize) >= file.size) ? file.size : start + chunkSize;

                fileReader.readAsArrayBuffer(blobSlice.call(file.file, start, end));
                currentChunk++;
                console.log('计算第' + currentChunk + '块');
            }
        },
        close() {
            this.uploader.cancel();
        },
        error(msg) {
            this.$notify({
                title: '错误',
                message: msg,
                type: 'error',
                duration: 2000
            });
        }
    }
};
</script>

转载请注明出处或者链接地址:https://www.qianduange.cn//article/17354.html
标签
评论
发布的文章

安装Nodejs后,npm无法使用

2024-11-30 11:11:38

大家推荐的文章
会员中心 联系我 留言建议 回顶部
复制成功!