vue自定义组件-文件上传

学习目标:

自定义文件上传组件


学习内容:

代码如下

<template>
    <div>
        <div class="container">
            <div class="handle-box">
                <div
                    id="extend-upload-chooseFile"
                    style="float: left;margin: 0px 10px;"
                    v-show="showOperationBtn1"
                >
                    <i class="el-icon-plus"></i>
                    选择文件
                </div>
                <el-button
                    type="success"
                    :icon="uploadStaus"
                    size="small"
                    class="handle-del mr10"
                    @click="uploadToServer()"
                    :disabled="uploadBtnDisabled"
                    v-show="showOperationBtn2"
                >开始上传</el-button>
                <el-button
                    type="danger"
                    icon="el-icon-close"
                    size="small"
                    class="handle-del mr10"
                    @click="clearFiles()"
                    :disabled="uploadBtnDisabled"
                    v-show="showOperationBtn3"
                >清空文件</el-button>
            </div>
            <div class="showMsg">支持上传的文件后缀:{{ options.fileType }}</div>
            <div class="showMsg">支持上传数:{{ fileNumLimit }}</div>
            <el-table :data="fileListData" style="width: 100%">
                <el-table-column prop="fileName" label="文件名称" width="180" align="center"></el-table-column>
                <el-table-column prop="fileSize" label="文件大小" width="120" align="center"></el-table-column>
                <el-table-column prop="progress" label="进度" align="center"></el-table-column>
                <el-table-column label="操作" width="200" fixed="right" align="center">
                    <template v-slot="scope">
                        <el-button
                            type="text"
                            class="red"
                            :icon="scope.row.suspendFileContent === '暂停' ? 'el-icon-sort' : 'el-icon-caret-right'"
                            @click="suspendRow(scope.$index, scope.row)"
                            v-show="showOperationBtn4"
                        >{{ scope.row.suspendFileContent }}</el-button>
                        <el-button
                            type="text"
                            icon="el-icon-close"
                            class="red"
                            @click="removeRow(scope.$index, scope.row)"
                            v-show="showOperationBtn5"
                        >移除</el-button>
                        <el-button
                            type="text"
                            icon="el-icon-search"
                            class="red"
                            @click="seeFile(scope.$index, scope.row)"
                            v-show="showOperationBtn6"
                        >查看</el-button>
                    </template>
                </el-table-column>
            </el-table>
        </div>
    </div>
</template>
<script>
import $ from 'jquery'
import webUploader from 'webuploader'
export default {
    name: 'webupload',
    props: {
        headers: {
            type: String,
            default: ''
        },
        fileNumLimit: {
            type: Number,
            default: 500
        },
        fileSize: {
            type: Number,
            default: 100 * 1024 * 1024 * 1024
        },
        chunkSize: {
            type: Number,
            default: 5 * 1024 * 1024
        },
        uploadSuffixUrl: {
            type: String,
            default: 'http://localhost:8090'
        },
        options: {
            type: Object,
            default: {
                //允许上传的文件
                fileType: "doc,docx,pdf,xls,xlsx,ppt,pptx,gif,jpg,jpeg,bmp,png,rar,zip,mp4,avi",
                fileUploadUrl: "/upload/fileRecord/zone/upload",//上传地址
                fileCheckUrl: "/upload/fileRecord/zone/upload/md5Check",//检测文件是否存在url
                checkChunkUrl: "/upload/fileRecord/zone/upload/md5Check",//检测分片url
                mergeChunksUrl: "/upload/fileRecord/zone/upload/merge/",//合并文件请求地址
                headers: {}
            }
        },
        fileListData: {
            type: Array,
            default: []
        },
        showUploadBtn: {
            type: String,
            default: "123456"
        },
        fileCode: {
            type: String,
            default: "siteDocument"
        }

    },
    data() {
        return {
            uploader: {},
            uploadBtnDisabled: false,
            uploadStaus: "el-icon-upload",
            fList: [{
                numbers: 1,
                fileName: "",
                fileSize: "120",
                progress: "20%",
                oper: ""
            }],//文件集合
            showOperationBtn1: this.showUploadBtn.lastIndexOf("1") > -1,
            showOperationBtn2: this.showUploadBtn.lastIndexOf("2") > -1,
            showOperationBtn3: this.showUploadBtn.lastIndexOf("3") > -1,
            showOperationBtn4: this.showUploadBtn.lastIndexOf("4") > -1,
            showOperationBtn5: this.showUploadBtn.lastIndexOf("5") > -1,
            showOperationBtn6: this.showUploadBtn.lastIndexOf("6") > -1,
        }
    },
    mounted() {
        this.register();
        this.createUploader();
        this.events();
    },
    methods: {
        createUploader() {
            var fileType = this.options.fileType;
            this.uploader = webUploader.create({
                // 不压缩image
                resize: false,
                // swf文件路径
                swf: '../../../assets/Uploader.swf', // swf文件路径
                // 默认文件接收服务端。
                server: this.uploadSuffixUrl + this.options.fileUploadUrl,
                pick: {
                    id: '#extend-upload-chooseFile',//指定选择文件的按钮容器,不指定则不创建按钮。注意 这里虽然写的是 id, 不仅支持 id, 还支持 class, 或者 dom 节点。
                    multiple: true //开启文件多选
                },
                // fileSingleSizeLimit:fileSize,//单个文件大小
                accept: [{
                    title: 'file',
                    extensions: fileType,
                    mimeTypes: this.buildFileType(fileType)
                }],
                // 单位字节,如果图片大小小于此值,不会采用压缩。512k  512*1024,如果设置为0,原图尺寸大于设置的尺寸就会压缩;如果大于0,只有在原图尺寸大于设置的尺寸,并且图片大小大于此值,才会压缩
                compressSize: 0,
                fileNumLimit: this.fileNumLimit,//验证文件总数量, 超出则不允许加入队列,默认值:undefined,如果不配置,则不限制数量
                fileSizeLimit: 100 * 1024 * 1024 * 1024, //1kb=1024*1024,验证文件总大小是否超出限制, 超出则不允许加入队列。
                fileSingleSizeLimit: this.fileSize, //验证单个文件大小是否超出限制, 超出则不允许加入队列。
                chunked: true,//是否开启分片上传
                threads: 1,
                chunkSize: this.chunkSize,//如果要分片,每一片的文件大小
                prepareNextFile: false,//在上传当前文件时,准备好下一个文件,请设置成false,不然开启文件多选你浏览器会卡死
                formData: {
                    fileCode: this.fileCode
                }
            });
        },
        register() {//注册函数
            var uploadSuffixUrl = this.uploadSuffixUrl;
            var that = this;
            var options = this.options;
            var headers = options.headers || {};
            var fileCheckUrl = uploadSuffixUrl + options.fileCheckUrl;//检测文件是否存在url
            var checkChunkUrl = uploadSuffixUrl + options.checkChunkUrl;//检测分片url
            var mergeChunksUrl = uploadSuffixUrl + options.mergeChunksUrl;//合并文件请求地址
            var fileCode = this.fileCode

            //监控文件上传的三个时间点(注意:该段代码必须放在WebUploader.create之前)
            //时间点1::所有分块进行上传之前(1.可以计算文件的唯一标记;2.可以判断是否秒传)
            //时间点2: 如果分块上传,每个分块上传之前(1.询问后台该分块是否已经保存成功,用于断点续传)
            //时间点3:所有分块上传成功之后(1.通知后台进行分块文件的合并工作)
            webUploader.Uploader.register({
                "before-send-file": "beforeSendFile",
                "before-send": "beforeSend",
                "after-send-file": "afterSendFile"
            }, {
                //时间点1::所有分块进行上传之前调用此函数
                beforeSendFile: function (file) {//利用md5File()方法计算文件的唯一标记符
                    //创建一个deffered
                    var deferred = webUploader.Deferred();
                    //1.计算文件的唯一标记,用于断点续传和秒传,获取文件前20m的md5值,越小越快,防止碰撞,把文件名文件大小和md5拼接作为文件唯一标识
                    (new webUploader.Uploader()).md5File(file, 0, 10 * 1024 * 1024).progress(function (percentage) {
                    }).then(function (val) {
                        file.fileMd5 = val;
                        //2.请求后台是否保存过该文件,如果存在,则跳过该文件,实现秒传功能
                        $.ajax({
                            type: "POST",
                            url: fileCheckUrl,
                            headers: headers,
                            data: {
                                checkType: 1,
                                contentType: file.type,
                                zoneTotalMd5: val,
                                fileCode: fileCode
                            },
                            dataType: "json",
                            success: (response) => {
                                if (response.status == 0) {
                                    that.$emit('fileInfo', response.data)
                                    that.uploader.skipFile(file);
                                    that.setTableBtn(file.id, "文件秒传", response.data.networkPath);
                                    that.$notify.success({
                                        showClose: true,
                                        message: `[ ${file.name} ]文件秒传`
                                    });
                                    //如果存在,则跳过该文件,秒传成功
                                    that.fList.push(response.data);
                                    deferred.reject();
                                } else {
                                    if (response.code === 30001) {//判断是否支持此类文件上传
                                        var m = response.message + ",文件后缀:" + file.ext;
                                        that.uploader.skipFile(file);
                                        that.setTableBtn(file.id, m);
                                        //如果存在,则跳过该文件,秒传成功
                                        that.fList.push(response.data);
                                        deferred.reject();
                                    } else {
                                        //继续上传
                                        deferred.resolve();
                                    }
                                }
                            }
                        });

                    });
                    //返回deffered
                    return deferred.promise();
                },
                //时间点2:如果有分块上传,则 每个分块上传之前调用此函数
                //block:代表当前分块对象
                beforeSend: function (block) {//向后台发送当前文件的唯一标记,用于后台创建保存分块文件的目录
                    //1.请求后台是否保存过当前分块,如果存在,则跳过该分块文件,实现断点续传功能
                    var deferred = webUploader.Deferred();
                    //请求后台是否保存完成该文件信息,如果保存过,则跳过,如果没有,则发送该分块内容
                    (new webUploader.Uploader()).md5File(block.file, block.start, block.end).progress(function (percentage) {
                    }).then(function (val) {
                        block.zoneMd5 = val;
                        $.ajax({
                            type: "POST",
                            url: checkChunkUrl,
                            headers: headers,
                            data: {
                                checkType: 2,
                                zoneTotalMd5: block.file.fileMd5,
                                zoneMd5: block.zoneMd5,
                                fileCode: fileCode
                            },
                            dataType: "json",
                            success: function (response) {
                                if (response.status == 0) {
                                    //分块存在,跳过该分块
                                    deferred.reject();
                                } else {
                                    //分块不存在或者不完整,重新发送该分块内容
                                    deferred.resolve();
                                }
                            }
                        }
                        );
                    });
                    return deferred.promise();
                },
                //时间点3:所有分块上传成功之后调用此函数
                afterSendFile: function (file) {//前台通知后台合并文件
                    //1.如果分块上传,则通过后台合并所有分块文件
                    //请求后台合并文件
                    $.ajax({
                        type: "POST",
                        url: mergeChunksUrl + file.fileMd5,
                        headers: headers,
                        dataType: "JSON",
                        success: function (response) {
                            if (response.status == 0) {//存在了,+1
                                var data = response.data.fileInfo;
                                that.uploader.skipFile(file);
                                that.setTableBtn(file.id, '上传成功', data.networkPath);
                                that.fList.push(data);
                                that.$emit('fileInfo', data)
                            } else {
                                console.log(response.message);
                            }
                        }
                    });
                }
            });
        },
        events() {
            var that = this;
            var uplaod = this.uploader;
            //当文件添加进去
            uplaod.on('fileQueued', function (file) {
                var fileSize = that.formatFileSize(file.size);
                var row = { fileId: file.id, fileName: file.name, fileSize: fileSize, validateMd5: '0%', progress: "等待上传", state: '就绪', suspendFileContent: '暂停' };
                console.log("this.fileListData:", that.fileListData);
                that.fileListData.push(row);
            });

            //监听进度条,更新进度条信息
            uplaod.on('uploadProgress', function (file, percentage) {
                that.$emit('uploadProgress', (percentage * 100).toFixed(2))
                that.setTableBtn(file.id, (percentage * 100).toFixed(2) + '%');
            });

            /**上传之前**/
            uplaod.on('uploadBeforeSend', function (block, data, headers) {
                data.fileMd5 = block.file.fileMd5;
                data.contentType = block.file.type;
                data.chunks = block.file.chunks;
                data.zoneTotalMd5 = block.file.fileMd5;
                data.zoneMd5 = block.zoneMd5;
                data.zoneTotalCount = block.chunks;
                data.zoneNowIndex = block.chunk;
                data.zoneTotalSize = block.total;
                data.zoneStartSize = block.start;
                data.zoneEndSize = block.end;
                headers.Authorization = that.options.headers.Authorization;
            });

            //错误信息监听
            uplaod.on('error', function (handler) {

                if (handler == 'F_EXCEED_SIZE') {
                    that.$message.error({
                        showClose: true,
                        dangerouslyUseHTMLString: true,
                        message: '上传的单个太大!
最大支持'
+ that.formatFileSize(that.fileSize) + '!
操作无法进行,如有需求请联系管理员'
}); } else if (handler == 'Q_TYPE_DENIED') { that.$message.error({ showClose: true, dangerouslyUseHTMLString: true, message: '不允许上传此类文件。
操作无法进行,如有需求请联系管理员'
}); } }); /**从文件队列移除**/ uplaod.on('fileDequeued', function (file) { // delete percentages[ file.id ]; }); //当文件上传成功时触发。file {ArchivesFile} File对象, response {Object}服务端返回的数据 uplaod.on('uploadSuccess', function (file, response) { // debugger; if (response.status == 0) { that.setTableBtn(file.id, '正在校验文件...'); } }) //所有文件上传成功后 uplaod.on('uploadFinished', () => {//成功后 that.uploadBtnDisabled = false; that.uploadStaus = "el-icon-upload"; that.$message.success({ showClose: true, message: '文件上传结束' }); that.$emit('uploadBtnDisabled', this.uploadBtnDisabled) }); uplaod.on('all', function (type) { // console.log(type); var state = '' //监听事件类型 if (type === 'startUpload') { state = 'uploading'; window.onbeforeunload = function (event) { if (state === 'uploading' || state === 'paused') { // console.log("你要放弃本次上传,离开页面吗?"); } } } else if (type === 'stopUpload') { state = 'paused'; } else if (type === 'uploadFinished') { state = 'done'; } //按钮字体切换 if (state === 'uploading') { // $btn.text('暂停'); } else { // $btn.text('开始'); } }); }, setTableBtn(fileId, showmsg, networkPath) { var fileList = this.fileListData; for (var i = 0; i < fileList.length; i++) { if (fileList[i].fileId == fileId) { this.fileListData[i].progress = showmsg; this.fileListData[i].networkPath = networkPath || ""; } } }, suspendRow(index, row) { if (row.progress === '等待上传') { this.$message.warning("文件等待上传") return; } if (row.progress === '上传成功' || row.progress === '文件秒传') { this.$message.warning("文件已上传") return; } if (row.progress === '正在校验文件...') { this.$message.warning("正在校验文件") return; } if (row.suspendFileContent === '暂停') { if (this.uploader) { this.uploader.stop(true); } row.suspendFileContent = '继续' } else { if (this.uploader) { this.uploader.upload(); } row.suspendFileContent = '暂停' } }, removeRow(index, row) { if (this.uploader) { this.uploader.removeFile(row.fileId); } this.fileListData.splice(index, 1); }, seeFile(index, row) { var npath = row.networkPath; if (this.strIsNull(npath)) { this.$message.error({ showClose: true, message: '文件未上传,请等待文件上传完成后,方可查看' }); return; } var filens = npath.substring(npath.lastIndexOf(".") + 1); if (filens == "png" || filens == "jpg" || filens == "jpeg" || filens == "gif") {//图片,在当前窗口查看 this.$message.success({ dangerouslyUseHTMLString: true, showClose: true, message: `<img src="${this.uploadSuffixUrl + npath}" style="max-width: 80%;max-height: 80%;"/>` }); } else { window.open(this.uploadSuffixUrl + npath); } }, uploadToServer() { if (this.fileListData.length <= 0) { this.$message.error({ showClose: true, message: '没有上传的文件' }); return; } this.uploadBtnDisabled = true; this.$emit('uploadBtnDisabled', this.uploadBtnDisabled) this.uploadStaus = "el-icon-loading"; $("#extent-button-uploader").text("正在上传,请稍等..."); // $("#extent-button-uploader").addClass('layui-btn-disabled'); this.uploader.upload(); }, clearFiles() { var that = this; if (that.fileListData.length > 0) { that.uploadBtnDisabled = false; that.uploadStaus = "el-icon-upload"; that.uploader.reset(); that.fileListData.length = 0; } this.$emit('uploadProgress', 0) }, beginUploadFile(index, row) { this.uploadBtnDisabled = false; this.$emit('uploadBtnDisabled', this.uploadBtnDisabled) this.uploadStaus = "el-icon-upload"; this.uploader.upload(); }, stopUploadFile(index, row) { this.uploadBtnDisabled = false; this.$emit('uploadBtnDisabled', this.uploadBtnDisabled) this.uploadStaus = "el-icon-upload"; this.uploader.stop(); }, buildFileType(fileType) { var ts = fileType.split(','); var ty = ''; for (var i = 0; i < ts.length; i++) { ty = ty + "." + ts[i] + ","; } return ty.substring(0, ty.length - 1) }, strIsNull(str) { if (typeof str == "undefined" || str == null || str == "") return true; else return false; }, formatFileSize(size) { var fileSize = 0; if (size / 1024 > 1024) { var len = size / 1024 / 1024; fileSize = len.toFixed(2) + "MB"; } else if (size / 1024 / 1024 > 1024) { var len = size / 1024 / 1024; fileSize = len.toFixed(2) + "GB"; } else { var len = size / 1024; fileSize = len.toFixed(2) + "KB"; } return fileSize; }, } } </script> <style> .container { padding: 30px; background: #fff; border: 1px solid #ddd; border-radius: 5px; } .handle-box { margin-bottom: 20px; } #picker div:nth-child(2) { width: 100% !important; height: 100% !important; } .webuploader-container { position: relative; } .webuploader-element-invisible { position: absolute !important; clip: rect(1px 1px 1px 1px); /* IE6, IE7 */ clip: rect(1px, 1px, 1px, 1px); } .webuploader-pick { position: relative; display: inline-block; cursor: pointer; background: #409eff; padding: 8px 12px; color: #fff; font-size: 10px; text-align: center; border-radius: 3px; overflow: hidden; } .webuploader-pick-hover { background: #409eff; } .showMsg { margin: 5px; background: radial-gradient(#d2b8b8, transparent); } </style>

引用组件

<WebUpload
        ref="webuploader"
        :fileNumLimit="fileNumLimit"
        :fileSize="fileSize"
        :chunkSize="chunkSize"
        :uploadSuffixUrl="uploadSuffixUrl"
        :options="options"
        :fileListData="fileList"
        :fileCode="fileCode"
        @fileInfo="fileInfo"
        @uploadBtnDisabled="uploadBtnDisabled"
        @uploadProgress="uploadProgress"
      ></WebUpload>

效果图
vue自定义组件-文件上传_第1张图片


学习时间:

2022-01-14


总结

还待完善…

你可能感兴趣的:(前端,vue组件,vue.js,前端,javascript)