当前位置:   article > 正文

vue实现大文件分片上传 vue-simple-uploader_vue-simple-uploader分片上传

vue-simple-uploader分片上传

首先为什么要分片上传?
大部分小白使用element-ui中上传组件,但是直接用它上传大文件会 超时 或者Request Entity Too Large(请求实体太大)这种问题。

1. 使用插件 vue-simple-uploader

我的这个可以自定义样式(没懂的留言给我)

1.1 customUploader封装组件

上代码:


<template>
  <div id="global-uploader" :class="{'global-uploader-single': !global}">
    <uploader
        ref="uploader"
        :options="initOptions"
        :fileStatusText="fileStatusText"
        :autoStart="false"
        @file-added="onFileAdded"
        @file-success="onUploadSuccess"
        @file-progress="onFileProgress"
        @file-error="onFileError"
        class="uploader-app">

      <uploader-unsupport></uploader-unsupport>
      <div @click="clickUploader" :style="{width}">
        <uploader-drop
            class="custom_uploader_drop"
            :style="{width}"
            v-if="!isUpload"
            v-loading="isMd5Upload"
            element-loading-text="正在读取中">
          <slot name="customContent"></slot>
          <uploader-btn ref="uploadBtn" style="display: none" />
        </uploader-drop>
        <div v-if="isUpload" class="upload_process_box">
          <div>文件名:{{fileName}}</div>

            <el-progress  :percentage="uploadProcessNum"></el-progress>
<!--            <el-progress v-else :percentage="syncUploadProcessNum"></el-progress>-->
          <div v-if="isMd5Upload">
            正在读取文件中 - {{md5ProgressText}}
          </div>
          <div v-if="!isSyncUpload&&!isMd5Upload">
            正在上传至服务器 - <span>{{uploadSpeed}} M/s</span>
          </div>
          <div v-if="isSyncUpload">
            正在上传至华为云,稍等会儿 (*^<i class="el-icon-loading" />^*)
          </div>
        </div>
      </div>


<!--      <uploader-list v-show="panelShow">-->
<!--        <div class="file-panel" slot-scope="props" :class="{ collapse: collapse }">-->
<!--          <div class="file-title">-->
<!--            <div class="title">文件列表</div>-->
<!--            <div class="operate">-->
<!--              <el-button @click="collapse = !collapse" type="text" :title="collapse ? '展开' : '折叠'">-->
<!--                <i class="iconfont" :class="collapse ? 'el-icon-full-screen' : 'el-icon-minus'"></i>-->
<!--              </el-button>-->
<!--              <el-button @click="close" type="text" title="关闭">-->
<!--                <i class="el-icon-close"></i>-->
<!--              </el-button>-->
<!--            </div>-->
<!--          </div>-->

<!--          <ul class="file-list">-->
<!--            <li-->
<!--                class="file-item"-->
<!--                v-for="file in props.fileList"-->
<!--                :key="file.id">-->
<!--              <uploader-file-->
<!--                  :class="['file_' + file.id, customStatus]"-->
<!--                  ref="files"-->
<!--                  :file="file"-->
<!--                  :list="true"-->
<!--              ></uploader-file>-->
<!--            </li>-->
<!--            <div class="no-file" v-if="!props.fileList.length">-->
<!--              <i class="iconfont icon-empty-file"></i> 暂无待上传文件-->
<!--            </div>-->
<!--          </ul>-->
<!--        </div>-->
<!--      </uploader-list>-->
    </uploader>
  </div>
</template>

<script>
import { ACCEPT_CONFIG } from './js/config'
import Bus from './js/bus'
import SparkMD5 from 'spark-md5'
// import { mergeSimpleUpload } from '@/api'
// 封装的网络请求promise
import { uploadFile,startOriginUploadFile, queryUploadFileProgress,startMergeFile } from './js/service.js'

import { getToken } from "@/utils/auth";

// let urll = process.env.VUE_APP_BASE_API + '/wk-upload/upload/upload';

// let urll = 'http://192.168.1.111:9999/wk-upload/upload/upload';

export default {
  props: {
    global: {
      type: Boolean,
      default: false
    },
    // 发送给服务器的额外参数
    params: {
      type: Object
    },
    options: {
      type: Object
    },
    // 宽度
    width: {
      type: [Number,String],
      default: 100,
      validator(value) {
        return typeof value === 'String' ? value : (value + 'px')
      }
    }
  },

  data() {
    return {
      // actionResourceUrl: process.env.VUE_APP_BASE_API + '/upload/upload',
      initOptions: {
        target: this.$api.actionBigFileUrl,
        headers: {
          Authorization: "Bearer " + getToken(),
          // 'Content-Type': 'application/json;charset=UTF-8',
        },
        chunkSize: 1024*1024*10,//10485760 //10000000, //1024 * 1024 * 3,  //3MB 10000000
        // chunkSize: '2048000',
        fileParameterName: 'file', //上传文件时文件的参数名,默认file
        singleFile: true, // 启用单个文件上传。上传一个文件后,第二个文件将超过现有文件,第一个文件将被取消。
        maxChunkRetries: 3,  //最大自动失败重试上传次数
        testChunks: false,     //是否开启服务器分片校验
        // simultaneousUploads: 3, //并发上传数
        // 服务器分片校验函数,秒传及断点续传基础
        // checkChunkUploadedByResponse: (chunk, message) => {
        //   let skip = false
        //   //
        //   // try {
        //   //   let objMessage = JSON.parse(message)
        //   //   if (objMessage.skipUpload) {
        //   //     skip = true
        //   //   } else {
        //   //     skip = (objMessage.uploaded || []).indexOf(chunk.offset + 1) >= 0
        //   //   }
        //   // } catch (e) {}
        //
        //   return skip
        // },
        query: (file, chunk) => {
          return {
            ...file.params
          }
        }
      },
      fileStatusText: {
        success: '上传成功',
        error: '上传失败',
        uploading: '上传中',
        paused: '已暂停',
        waiting: '等待上传'
      },
      panelShow: false, //选择文件后,展示上传panel
      collapse: false,
      customParams: {},
      customStatus: '',

      isUploadOk: false,
      isUploadErr: false,
      isStartUpload: false, // 开始上传
      md5ProgressText: 0,
      isMd5Upload: false, // 计算md5状态
      isUpload: false, // 正在上传
      uploadProcessNum: 0, // 上传进度
      uploadSpeed: 0, // 上传速度
      fileName: '', // 文件名
      isSyncUpload: false, // 是否在同步远程数据
      syncUploadProcessNum: 0, // 同步远程数据
      response: null, // 上传成功
      queryTimer: null, // 轮询计时器

      socket: null,
    }
  },
  computed: {
    // Uploader实例
    uploader() {
      return this.$refs.uploader.uploader
    }
  },

  methods: {
    // 自定义options
    customizeOptions(opts) {
      // 自定义上传url
      if (opts.target) {
        this.uploader.opts.target = opts.target
      }

      // 是否可以秒传、断点续传
      if (opts.testChunks !== undefined) {
        this.uploader.opts.testChunks = opts.testChunks
      }

      // merge 的方法,类型为Function,返回Promise
      this.mergeFn = opts.mergeFn || uploadFile

      // 自定义文件上传类型
      let input = document.querySelector('#global-uploader-btn input')
      let accept = opts.accept || ACCEPT_CONFIG.getAll()
      input.setAttribute('accept', accept.join())
    },
    clickUploader(e) {
      // console.log(e)
      this.$refs.uploadBtn.$el.click()
    },
    // 上传前
    onFileAdded(file) {
      // this.panelShow = true
      // this.emit('fileAdded')

      // 将额外的参数赋值到每个文件上,以不同文件使用不同params的需求
      // file.params = this.customParams

      // 计算MD5
      this.computeMD5(file).then((result) => this.startUpload(result))
    },
    /**
     * 计算md5值,以实现断点续传及秒传
     * @param file
     * @returns Promise
     */
    computeMD5(file) {
      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 = this.initOptions.chunkSize;

      let chunks = Math.ceil(file.size / chunkSize)
      let spark = new SparkMD5.ArrayBuffer()
      // 获取文件名
      const fileInfo = file.uploader.fileList[0]
      this.fileName = fileInfo.name

      // 文件状态设为"计算MD5"
      // this.statusSet(file.id, 'md5')
      this.isMd5Upload = true;
      this.isUpload = true;
      file.pause()
      loadNext()

      return new Promise((resolve, reject) => {
        fileReader.onload = (e) => {
          spark.append(e.target.result)
          if (currentChunk < chunks) {
            currentChunk++
            loadNext()

            // 实时展示MD5的计算进度
            this.$nextTick(() => {
              this.md5ProgressText = ((currentChunk/chunks)*100).toFixed(0)+'%'
            })

          } else {
            let md5 = spark.end()

            // md5计算完毕
            resolve({md5, file})
            // console.log(file);
            // 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()
          reject()
        }
      })

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

        fileReader.readAsArrayBuffer(blobSlice.call(file.file, start, end))
      }
    },

    // md5计算完毕,开始上传
    startUpload({md5, file}) {
      file.uniqueIdentifier = md5
      file.resume();
      this.isMd5Upload = false;
      this.isStartUpload = true;
      // this.statusRemove(file.id)
    },
    // 上传中
    onFileProgress(rootFile, file, chunk) {
      // console.log(
      //     `上传中 ${file.name},chunk:${chunk.startByte / 1024 / 1024} ~ ${
      //         chunk.endByte / 1024 / 1024
      //     }`
      // )
      // let index = this.findFileById(file.uniqueIdentifier),//通过index来获取对应的文件progress
      //     p = Math.round(file.progress()*100);
      // if(index > -1){
      //   if(p < 100){
      //     console.log(p)
      //   }
        // this.fileList[index].status = file.status;
      // }
      // console.log(rootFile)
      // let p = this.$refs.uploader.progress()
      // console.log(p)
      let uploader = this.$refs.uploader.uploader;
      this.uploadProcessNum = Math.floor(uploader.progress() * 100)
      this.emit('onUploadProcess',uploader.progress());


      // let averageSpeed = uploader.averageSpeed
      let averageSpeed = uploader.averageSpeed
      // let timeRemaining = uploader.timeRemaining()
      // let uploadedSize = uploader.sizeUploaded()
      let speed = averageSpeed / 1000 / 10;
      this.uploadSpeed = speed.toFixed(2);
      // console.log(speed.toFixed(2) + 'M/s')
    },
    // 上传中转站成功
    onUploadSuccess(rootFile, file, response, chunk) {
      let res1 = JSON.parse(response);
      if(res1.code===200) {
       // 开始merge
        console.log(rootFile.uniqueIdentifier);
        const body = {
          totalChunks: rootFile.chunks.length,
          md5File: rootFile.uniqueIdentifier,
          fileName: rootFile.name
        }
        console.log(file)
        startMergeFile(body).then(res=>{
          // 上传到华为云
          this.onUploadSuccessFinally({rootFile, file, res, chunk})
        })
      }else{
        this.error('上传失败')
        this.$emit('onUploadError',res1)
      }

      // 服务端自定义的错误(即http状态码为200,但是是错误的情况),这种错误是Uploader无法拦截的
      // if (!res.result) {
      //   this.error(res.message)
      //   // 文件状态设为“失败”
      //   this.statusSet(file.id, 'failed')
      //   return
      // }
      // return;
      // 如果服务端返回了需要合并的参数
      // if(res.needMerge) {
      //   // 文件状态设为“合并中”
      //   this.statusSet(file.id, 'merging')
      //
      //   this.mergeFn({
      //     tempName: res.tempName,
      //     fileName: file.name,
      //     ...file.params
      //   })
      //       .then((res) => {
      //         // 文件合并成功
      //         this.emit('fileSuccess')
      //
      //         this.statusRemove(file.id)
      //       })
      //       .catch((e) => {})
      //
      //   // 不需要合并
      // } else {
      //   this.emit('fileSuccess')
      //   console.log('上传成功')
      // }
    },
    // 开始上传至华为云
    onUploadSuccessFinally(data) {
     // console.log(data)
      const {rootFile, file, res, chunk} = data
      let body = {
        id: res.data.id
      }
      // try {
        // 请求上传远程开始
        this.isSyncUpload = true;
         startOriginUploadFile(body).then(res1=>{
           this.isUpload = false;
           this.isSyncUpload = false;
           this.$emit('onUploadSuccess',res1)
         }).catch(err=>{
             this.isUpload = false;
             this.$emit('onUploadError',e)
             this.error('上传华为云失败')
             clearInterval(this.queryTimer)
         })
        // this.uploadProcessNum = 0;

          // this.queryTimer = setInterval(()=>{
          //       this.queryProcess(body).then(res=>{
                //   console.log(res);
                //   this.isSyncUpload = true;
                //   if(res.data.process&&res.data.process<100) {
                //     this.syncUploadProcessNum = res.data.process
                //   }else{
                //     this.syncUploadProcessNum = 100;
                //     this.isUploadOk = true;
                //     this.isUpload = false;
                //     this.$emit('onUploadSuccess',res)
                //     clearInterval(this.queryTimer)
                //   }
                // }).catch(err=>{
                //   this.isUpload = false;
                //   this.$emit('onUploadError',err)
                //   this.error('上传华为云失败')
                //   clearInterval(this.queryTimer)
                // })
            // },3000)
      // } catch (e) {
      //   this.isUpload = false;
      //   this.$emit('onUploadError',e)
      //   this.error('上传华为云失败')
      //   clearInterval(this.queryTimer)
      // }

      // console.log('上传成功')
      // this.$emit('onUploadSuccess',res);
      // setInterval(()=>{
      //
      // },1000)
      // queryUploadFileProgress().then(res=>{})
    },
    // 获取上传华为云进度
    queryProcess(body) {

      // return new Promise((resolve,reject)=>{
        // queryUploadFileProgress(body).then(res=>{
        //     if(res.code===200) {
        //       resolve(res)
        //     }else{
        //       reject(res)
        //     }
        // }).catch(err=>{
        //   reject(err)
        // })
      // })
    },
    // 上传失败
    onFileError(rootFile, file, response, chunk) {
      this.error('上传失败');
      this.$emit('onUploadError',response);
      this.isUpload = false;
    },
    // 取消
    close() {
      this.uploader.cancel()
      this.panelShow = false
    },
    /**
     * 新增的自定义的状态: 'md5'、'merging'、'transcoding'、'failed'
     * @param id
     * @param status
     */
    statusSet(id, status) {

      let statusMap = {
        md5: {
          text: '读取文件中',
          bgc: '#fff'
        },
        merging: {
          text: '合并中',
          bgc: '#e2eeff'
        },
        transcoding: {
          text: '转码中',
          bgc: '#e2eeff'
        },
        failed: {
          text: '上传失败',
          bgc: '#e2eeff'
        }
      }

      this.customStatus = status
      // this.$nextTick(() => {
      //   const statusTag = document.createElement('p')
      //   statusTag.className = `custom-status-${id} custom-status`
      //   statusTag.innerText = statusMap[status].text
      //   statusTag.style.backgroundColor = statusMap[status].bgc
      //
      //   const statusWrap = document.querySelector(`.file_${id} .uploader-file-status`)
      //   statusWrap.appendChild(statusTag)
      // })
    },
    // 移除状态
    statusRemove(id) {
      this.customStatus = ''
      // this.$nextTick(() => {
      //   const statusTag = document.querySelector(`.custom-status-${id}`)
      //   statusTag.remove()
      // })
    },

    emit(e) {
      // Bus.$emit(e)
      // this.$emit(e)
    },

    error(msg) {
      this.$notify({
        title: '错误',
        message: msg,
        type: 'error',
        duration: 2000
      })
    }
  },
  beforeDestroy() {
    clearInterval(this.queryTimer)
    // this.socket.onclose = (ee)=>{
    //
    // }
  }
}
</script>

<style lang="scss">
#global-uploader {
  &:not(.global-uploader-single) {
    position: fixed;
    z-index: 20;
    right: 15px;
    bottom: 15px;
    box-sizing: border-box;
  }

  .uploader-app {
    width: 520px;
  }

  .file-panel {
    background-color: #fff;
    border: 1px solid #e2e2e2;
    border-radius: 7px 7px 0 0;
    box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);

    .file-title {
      display: flex;
      height: 40px;
      line-height: 40px;
      padding: 0 15px;
      border-bottom: 1px solid #ddd;

      .operate {
        flex: 1;
        text-align: right;

        i {
          font-size: 18px;
        }
      }
    }

    .file-list {
      position: relative;
      height: 240px;
      overflow-x: hidden;
      overflow-y: auto;
      background-color: #fff;
      transition: all 0.3s;

      .file-item {
        background-color: #fff;
      }
    }

    &.collapse {
      .file-title {
        background-color: #e7ecf2;
      }
      .file-list {
        height: 0;
      }
    }
  }

  .no-file {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    font-size: 16px;
  }

  .uploader-file {
    &.md5 {
      .uploader-file-resume {
        display: none;
      }
    }
  }

  .uploader-file-icon {
    &:before {
      content: '' !important;
    }

    //&[icon='image'] {
    //  background: url(./images/image-icon.png);
    //}
    //&[icon=audio] {
    //  background: url(./images/audio-icon.png);
    //  background-size: contain;
    //}
    //&[icon='video'] {
    //  background: url(./images/video-icon.png);
    //}
    //&[icon='document'] {
    //  background: url(./images/text-icon.png);
    //}
    //&[icon=unknown] {
    //  background: url(./images/zip.png) no-repeat center;
    //  background-size: contain;
    //}
  }

  .uploader-file-actions > span {
    margin-right: 6px;
  }

  .custom-status {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 1;
  }
}

.custom_uploader_drop {
     background-color: rgba(176, 172, 172, 0.1) !important;
     cursor: pointer;
     border-radius: 5px;
  &:hover {
    border-color: #409eff !important;
  }
}
.upload_process_box {
  border-radius: 5px;
  border: 1px dashed #409eff;
  & > div {
    padding: 5px 0;
  }
}


/* 隐藏上传按钮 */
#global-uploader-btn {
  position: absolute;
  clip: rect(0, 0, 0, 0);
}

.global-uploader-single {
  #global-uploader-btn {
    position: relative;
  }
}

//.dot_tran {
//  animation-name: dot_tran_keyframe;
//  animation-duration: 0.1s;
//  animation-iteration-count: infinite;
//  .dot_tran_{
//    &:after {
//      content: '';
//    }
//  }
//
//}
//@keyframes dot_tran_keyframe {
//   0% {
//     .dot_tran_ {
//       &:after {
//         content: '.';
//       }
//     }
//   }
//  50% {
//    .dot_tran_ {
//      &:after {
//        content: '..';
//      }
//    }
//
//  }
//  100% {
//    .dot_tran_ {
//      &:after {
//        content: '...';
//      }
//    }
//  }
//}

</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
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • 322
  • 323
  • 324
  • 325
  • 326
  • 327
  • 328
  • 329
  • 330
  • 331
  • 332
  • 333
  • 334
  • 335
  • 336
  • 337
  • 338
  • 339
  • 340
  • 341
  • 342
  • 343
  • 344
  • 345
  • 346
  • 347
  • 348
  • 349
  • 350
  • 351
  • 352
  • 353
  • 354
  • 355
  • 356
  • 357
  • 358
  • 359
  • 360
  • 361
  • 362
  • 363
  • 364
  • 365
  • 366
  • 367
  • 368
  • 369
  • 370
  • 371
  • 372
  • 373
  • 374
  • 375
  • 376
  • 377
  • 378
  • 379
  • 380
  • 381
  • 382
  • 383
  • 384
  • 385
  • 386
  • 387
  • 388
  • 389
  • 390
  • 391
  • 392
  • 393
  • 394
  • 395
  • 396
  • 397
  • 398
  • 399
  • 400
  • 401
  • 402
  • 403
  • 404
  • 405
  • 406
  • 407
  • 408
  • 409
  • 410
  • 411
  • 412
  • 413
  • 414
  • 415
  • 416
  • 417
  • 418
  • 419
  • 420
  • 421
  • 422
  • 423
  • 424
  • 425
  • 426
  • 427
  • 428
  • 429
  • 430
  • 431
  • 432
  • 433
  • 434
  • 435
  • 436
  • 437
  • 438
  • 439
  • 440
  • 441
  • 442
  • 443
  • 444
  • 445
  • 446
  • 447
  • 448
  • 449
  • 450
  • 451
  • 452
  • 453
  • 454
  • 455
  • 456
  • 457
  • 458
  • 459
  • 460
  • 461
  • 462
  • 463
  • 464
  • 465
  • 466
  • 467
  • 468
  • 469
  • 470
  • 471
  • 472
  • 473
  • 474
  • 475
  • 476
  • 477
  • 478
  • 479
  • 480
  • 481
  • 482
  • 483
  • 484
  • 485
  • 486
  • 487
  • 488
  • 489
  • 490
  • 491
  • 492
  • 493
  • 494
  • 495
  • 496
  • 497
  • 498
  • 499
  • 500
  • 501
  • 502
  • 503
  • 504
  • 505
  • 506
  • 507
  • 508
  • 509
  • 510
  • 511
  • 512
  • 513
  • 514
  • 515
  • 516
  • 517
  • 518
  • 519
  • 520
  • 521
  • 522
  • 523
  • 524
  • 525
  • 526
  • 527
  • 528
  • 529
  • 530
  • 531
  • 532
  • 533
  • 534
  • 535
  • 536
  • 537
  • 538
  • 539
  • 540
  • 541
  • 542
  • 543
  • 544
  • 545
  • 546
  • 547
  • 548
  • 549
  • 550
  • 551
  • 552
  • 553
  • 554
  • 555
  • 556
  • 557
  • 558
  • 559
  • 560
  • 561
  • 562
  • 563
  • 564
  • 565
  • 566
  • 567
  • 568
  • 569
  • 570
  • 571
  • 572
  • 573
  • 574
  • 575
  • 576
  • 577
  • 578
  • 579
  • 580
  • 581
  • 582
  • 583
  • 584
  • 585
  • 586
  • 587
  • 588
  • 589
  • 590
  • 591
  • 592
  • 593
  • 594
  • 595
  • 596
  • 597
  • 598
  • 599
  • 600
  • 601
  • 602
  • 603
  • 604
  • 605
  • 606
  • 607
  • 608
  • 609
  • 610
  • 611
  • 612
  • 613
  • 614
  • 615
  • 616
  • 617
  • 618
  • 619
  • 620
  • 621
  • 622
  • 623
  • 624
  • 625
  • 626
  • 627
  • 628
  • 629
  • 630
  • 631
  • 632
  • 633
  • 634
  • 635
  • 636
  • 637
  • 638
  • 639
  • 640
  • 641
  • 642
  • 643
  • 644
  • 645
  • 646
  • 647
  • 648
  • 649
  • 650
  • 651
  • 652
  • 653
  • 654
  • 655
  • 656
  • 657
  • 658
  • 659
  • 660
  • 661
  • 662
  • 663
  • 664
  • 665
  • 666
  • 667
  • 668
  • 669
  • 670
  • 671
  • 672
  • 673
  • 674
  • 675
  • 676
  • 677
  • 678
  • 679
  • 680
  • 681
  • 682
  • 683
  • 684
  • 685
  • 686
  • 687
  • 688
  • 689
  • 690
  • 691
  • 692
  • 693
  • 694
  • 695
  • 696
  • 697
  • 698
  • 699
  • 700
  • 701
  • 702
  • 703
  • 704
  • 705
  • 706
  • 707
  • 708
  • 709
  • 710
  • 711
  • 712
  • 713
  • 714
1.2

<customStardingUploader
   v-if="!form.resourceUrl"
    width="400px"
    @onUploadSuccess="handleAvatarSuccessResource"
    @onUploadError="handleVideoErrorResource">
  <!--   自定义内容   -->
  <template #customContent>
    <div style="margin: 0 auto;width: fit-content;text-align: center">
      <div>将文件拖拽到此处</div>
      <div>或点击上传</div>
    </div>
  </template>
</customStardingUploader>

 // 上传视频成功
 handleAvatarSuccessResource(res, file) {
    this.form.resourceUrl = res.data;
    this.uploadLoading = false;
  },
  // 上传视频失败
  handleVideoErrorResource(err) {
    this.uploadLoading = false;
  },

  • 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
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/天景科技苑/article/detail/995826
推荐阅读
相关标签
  

闽ICP备14008679号