当前位置:   article > 正文

基于WebUploader实现大文件分片上传

基于webuploader

前言

前面叙述了如何利用vue-simple-uploader实现分片上传、断点续传和秒传;
本篇学习基于WebUploader实现这些功能
  • 1
  • 2

使用

1.在项目中引入webuploader

注意事项
1、插件基于jquery,
2、不支持npm导入(通过 import './webuploader'; 的方式引入webuploader,会报''caller', 'callee', and 'arguments' properties may not be accessed on strict mode ...'的错,)
  • 1
  • 2
  • 3

我们在项目index.html中进行静态引入资源
官网 上下载
Uploader.swf 和 webuploader.min.js,放到静态static文件下

在这里插入图片描述

注意事项
如遇到报错:Uncaught SyntaxError: Unexpected token ‘<‘,
是vue静态资源引入错误:https://blog.csdn.net/weixin_43909743/article/details/118804322
  • 1
  • 2
  • 3
  1. 封装上传组件upload.vue
    封装好的组件upload.vue如下,接口可以根据具体的业务进行扩展。
<template>
   <div class="upload">
   </div>
</template>

<script>
 import { getToken } from "@/utils/auth"; // headers里面必须传递的token
   export default {
       name: 'vue-upload',
       props: {
           accept: {
               type: Object,
               default: null,
           },
           // 上传地址
           url: {
               type: String,
               default: '',
           },
           // 上传最大数量 默认为100
           fileNumLimit: {
               type: Number,
               default: 100,
           },
           // 大小限制 默认2M
           fileSingleSizeLimit: {
               type: Number,
               default: 2048000,
           },
           // 上传时传给后端的参数,一般为token,key等
           formData: {
               type: Object,
               default: null
           },
           // 生成formData中文件的key,下面只是个例子,具体哪种形式和后端商议
           keyGenerator: {
               type: Function,
               default(file) {
                   const currentTime = new Date().getTime();
                   const key = `${currentTime}.${file.name}`;
                   return key;
               },
           },
           multiple: {
               type: Boolean,
               default: false,
           },
           // 上传按钮ID
           uploadButton: {
               type: String,
               default: '',
           },
       },
       data() {
           return {
               uploader: null
           };
       },
       mounted() {
           this.initWebUpload();
       },
       methods: {
           initWebUpload() {
               this.uploader = WebUploader.create({
                   auto: true, // 选完文件后,是否自动上传
                   // swf: '/static/lib/webuploader/Uploader.swf',  // swf文件路径 非必要
                   server: this.url,  // 文件接收服务端
                   pick: {
                       id: this.uploadButton,     // 选择文件的按钮
                       multiple: this.multiple,   // 是否多文件上传 默认false
                       label: '',
                   },
                   accept: this.getAccept(this.accept),  // 允许选择文件格式。
                   threads: 3,
                   fileNumLimit: this.fileNumLimit, // 限制上传个数
                   //fileSingleSizeLimit: this.fileSingleSizeLimit, // 限制单个上传图片的大小
                   formData: this.formData,  // 上传所需参数
                   chunked: true,          //分片上传
                   chunkSize: 2048000,    //分片大小
                   duplicate: true,  // 重复上传
                   headers: { Authorization: "Bearer " + getToken() },
               });
               // 当有文件被添加进队列的时候,添加到页面预览
               this.uploader.on('fileQueued', (file) => {
                   this.$emit('fileChange', file);
               });
               this.uploader.on('uploadStart', (file) => {
                   // 在这里可以准备好formData的数据
                   //this.uploader.options.formData.key = this.keyGenerator(file);
               });
               // 文件上传过程中创建进度条实时显示。
               this.uploader.on('uploadProgress', (file, percentage) => {
                   this.$emit('progress', file, percentage);
               });
               this.uploader.on('uploadSuccess', (file, response) => {
                   this.$emit('success', file, response);
               });
               this.uploader.on('uploadError', (file, reason) => {
                   console.error(reason);
                   this.$emit('uploadError', file, reason);
               });
               this.uploader.on('error', (type) => {
                   let errorMessage = '';
                   if (type === 'F_EXCEED_SIZE') {
                       errorMessage = `文件大小不能超过${this.fileSingleSizeLimit / (1024 * 1000)}M`;
                   } else if (type === 'Q_EXCEED_NUM_LIMIT') {
                       errorMessage = '文件上传已达到最大上限数';
                   } else {
                       errorMessage = `上传出错!请检查后重新上传!错误代码${type}`;
                   }
                   console.error(errorMessage);
                   this.$emit('error', errorMessage);
               });
               this.uploader.on('uploadComplete', (file, response) => {
                   this.$emit('complete', file, response);
               });
           },
           upload(file) {
               this.uploader.upload(file);
           },
           stop(file) {
               this.uploader.stop(file);
           },
           // 取消并中断文件上传
           cancelFile(file) {
               this.uploader.cancelFile(file);
           },
           // 在队列中移除文件
           removeFile(file, bool) {
               this.uploader.removeFile(file, bool);
           },
           getAccept(accept) {
               switch (accept) {
                   case 'text':
                       return {
                           title: 'Texts',
                           exteensions: 'doc,docx,xls,xlsx,ppt,pptx,pdf,txt',
                           mimeTypes: '.doc,docx,.xls,.xlsx,.ppt,.pptx,.pdf,.txt'
                       };
                       break;
                   case 'video':
                       return {
                           title: 'Videos',
                           exteensions: 'mp4',
                           mimeTypes: '.mp4'
                       };
                       break;
                   case 'image':
                       return {
                           title: 'Images',
                           exteensions: 'gif,jpg,jpeg,bmp,png',
                           mimeTypes: '.gif,.jpg,.jpeg,.bmp,.png'
                       };
                       break;
                   default: return accept
               }
           },
       },
   };
</script>

<style lang="scss">
   .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: #00b7ee;
       padding: 10px 15px;
       color: #fff;
       text-align: center;
       border-radius: 3px;
       overflow: hidden;
   }
   .webuploader-pick-hover {
       background: #00a2d4;
   }
   .webuploader-pick-disable {
       opacity: 0.6;
       pointer-events:none;
   }
</style>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  1. 使用组件
	<el-form-item v-show="form.struct == 'single'&&form.courseType == 2" label="视频文件">
      <div class="page">
          <div id="filePicker">选择文件</div>
          <div class="file-panel">
              <div class="file-list">
                  <ul class="file-item" :class="`file-${file.id}`" v-for="file in fileList1" v-show="!form.videoUrl">
                      <li class="file-type" :icon="fileCategory(file.ext)"></li>
                      <li class="file-name">{{file.name}}</li>
                      <li class="file-size">{{fileSize(file.size)}}</li>
                      <li class="file-status">上传中...</li>
                      <li class="progress"></li>
                      <li @click="remove1(file)">关闭</li>
                  </ul>
                  <div class="no-file" v-if="!fileList1.length&&!form.videoUrl"><i class="iconfont icon-empty-file"></i> 暂无待上传文件</div>
                  <div class="no-file" v-if="form.videoUrl">
                    <i class="iconfont icon-empty-file"></i> {{form.videoUrl}}
                    <button @click="form.videoUrl=''">删除</button>
                  </div>
              </div>
          </div>

          <vue-upload
                  :url="url1"
                  ref="uploader"
                  uploadButton="#filePicker"
                  @fileChange="fileChange"
                  @progress="onProgress"
                  @success="onSuccess"
          ></vue-upload>
      </div>
    </el-form-item>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

data数据

fileList1: [],
url1:process.env.VUE_APP_BASE_API + "/file?type=1",
  • 1
  • 2
computed: {
     uploader() {
         return this.$refs.uploader;
     }
 },
  • 1
  • 2
  • 3
  • 4
  • 5

methods:

fileChange(file) {
    if(this.fileList1.length){return this.$message.warning('一次只能上传一个文件')}
           if (!file.size) return;
           this.form.videoUrl=''
           this.fileList1.push(file);
           console.log(file);
   },
   onProgress(file, percent) {
       $(`.file-${file.id} .progress`).css('width', percent * 99 + '%');
       $(`.file-${file.id} .file-status`).html((percent * 99).toFixed(2) + '%');
   },
   onSuccess (file, response) {
       console.log('上传成功', response);
       this.fileList1=[]
       $(`.file-${file.id} .file-status`).html( '100%');
       this.form.videoUrl = response.data.url
   },
    resume(file) {
       this.uploader.upload(file);
    },
    stop(file) {
        this.uploader.stop(file);
    },
    remove1(file) {
        // 取消并中断文件上传
        this.uploader.cancelFile(file);
        // 在队列中移除文件
        this.uploader.removeFile(file, true);
        // 在ui上移除
        let index = this.fileList1.findIndex(ele => ele.id === file.id);
        this.fileList1.splice(index, 1);
    },
    fileSize(size) {
        return WebUploader.Base.formatSize(size);
    },
    fileCategory(ext) {
        let type = '';
        const typeMap = {
            image: ['gif', 'jpg', 'jpeg', 'png', 'bmp', 'webp'],
            video: ['mp4', 'm3u8', 'rmvb', 'avi', 'swf', '3gp', 'mkv', 'flv'],
            text: ['doc', 'txt', 'docx', 'pages', 'epub', 'pdf', 'numbers', 'csv', 'xls', 'xlsx', 'keynote', 'ppt', 'pptx']
        };
        Object.keys(typeMap).forEach((_type) => {
            const extensions = typeMap[_type];
            if (extensions.indexOf(ext) > -1) {
                type = _type
            }
        });
        return type
    }, 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50

css

<style lang="scss">
    $h-row: 50px;
    .file-panel {
        width: 100%;
        margin-top: 10px;
        box-shadow: 0 2px 12px 1px rgba(0, 0, 0, 0.1);
        > h2 {
            height: 40px;
            line-height: 40px;
            padding: 0 10px;
            border-radius: 4px 4px 0 0;
            border-bottom: 1px solid #ccc;
            background-color: #fff;
        }
        .file-list {
            position: relative;
            height: 100px;
            overflow-y: auto;
            background-color: rgb(250, 250, 250);
        }
        .file-item {
            position: relative;
            height: $h-row;
            line-height: $h-row;
            padding: 0 10px;
            border-bottom: 1px solid #ccc;
            background-color: #fff;
            z-index: 1;
            > li {
                display: inline-block;
            }
        }
        .file-type {
            width: 24px;
            height: 24px;
            vertical-align: -5px;
        }
        .file-name {
            width: 40%;
            margin-left: 10px;
        }
        .file-size {
            width: 20%;
        }
        .file-status {
            width: 20%;
        }
        .file-operate {
            width: 10%;
            > a {
                padding: 10px 5px;
                cursor: pointer;
                color: #666;
                &:hover {
                    color: #ff4081;
                }
            }
        }
        .file-type[icon=text] {
            // background: url(../../assets/images/icon/text-icon.png);
        }
        .file-type[icon=video] {
            // background: url(../../assets/images/icon/video-icon.png);
        }
        .file-type[icon=image] {
            // background: url(../../assets/images/icon/image-icon.png);
        }
        .progress {
            position: absolute;
            top: 0;
            left: 0;
            height: $h-row - 1;
            width: 0;
            background-color: #E2EDFE;
            z-index: -1;
        }
        .no-file {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            font-size: 16px;
        }
    }
</style>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  1. 结果图
    在这里插入图片描述

  2. 参考:

后端参考:https://glory.blog.csdn.net/article/details/114284285
参考链接:https://www.jb51.net/article/136113.htm
  • 1
  • 2
本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
  

闽ICP备14008679号