• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
魏无羡的小古板
博客园    首页    新随笔    联系   管理    订阅  订阅

vue 上传较大的文件

使用插件   vue-simple-uploader

npm install  vue-simple-uploader --save   

npm install  spark-md5 --save   

 

main.js 中添加 

import uploader from 'vue-simple-uploader';
Vue.use(uploader);
 
在应用页面中引入并使用
 
<uploader
                ref="uploader"
                :options="options"
                :autoStart='false'
                :multipl="false"
                :limit="1"
                :file-status-text="fileStatusText"
                @file-added="onFileAdded"
                @file-success="onFileSuccess"
                @file-progress="onFileProgress"
                @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>
 
import {ACCEPT_CONFIG} from './config';
import SparkMD5 from 'spark-md5';
(
  备注:'./config.js'是一个js文件存放上传文件类型:
export const ACCEPT_CONFIG = {
    image: ['.png', '.jpg', '.jpeg', '.gif', '.bmp'],
    video: ['.mp4', '.rmvb', '.mkv', '.wmv', '.flv'],
    document: ['.doc', '.docx', '.xls', '.xlsx', '.ppt', '.pptx', '.pdf', '.txt', '.tif', '.tiff','.rar','.zip'],
    getAll(){
        return [...this.image, ...this.video, ...this.document]
    },
};
)
data(){
return {
 options: {
            //目标上传 URL,默认POST
            target: process.env.VUE_APP_BASE_API+"/api/questionBank/uploadFile",
            //分块大小(单位:字节)
            chunkSize: '2048000',
            //上传文件时文件内容的参数名,对应chunk里的Multipart对象名,默认对象名为file
            fileParameterName: 'upfile',
            //失败后最多自动重试上传次数
            maxChunkRetries: 3,
            //是否开启服务器分片校验,对应GET类型同名的target URL
            testChunks: true,   
            /* 
            服务器分片校验函数,判断秒传及断点续传,传入的参数是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: {
onFileProgress(rootFile, file, chunk) { console.log(`上传中 ${file.name},chunk:${chunk.startByte / 1024 / 1024} ~ ${chunk.endByte / 1024 / 1024}`) },
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";
        // mergeFile(file).then( responseData=> {
        //     if(responseData.data.code === 415){
        //         console.log("合并操作未成功,结果码:"+responseData.data.code);
        //     }
        // }).catch(function (error){
        //     console.log("合并后捕获的未知异常:"+error);
        // });
    },
    onFileError(rootFile, file, response, chunk) {
        console.log('上传完成后异常信息:'+response);
    },
    /**
     * 计算md5,实现断点续传及秒传
     * @param file
     */
    computeMD5(file) {
        file.pause();
        console.log(process.env.VUE_APP_BASE_API)
        //单个文件的大小限制2G
        let fileSizeLimit = 2 * 1024 * 1024 * 1024;
        console.log("文件大小:"+file.size);
        console.log("限制大小:"+fileSizeLimit);
        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
        })
    },
}

参考地址:https://www.cnblogs.com/xiahj/p/vue-simple-uploader.html

posted @ 2021-09-17 09:53  魏无羡的小古板  阅读(1051)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3