美文网首页
vue+element 实现和后端交互的上传文件功能

vue+element 实现和后端交互的上传文件功能

作者: 好名字都让你们用了 | 来源:发表于2021-07-12 14:36 被阅读0次
    :组件中api 项目中用到的 ,各位根据各自进行更换

    1:主要上传组件代码

    <template>
      <div class='upload'>
        <el-upload ref='upload' :class='{has: isShowHasClass, unshow: hideUploadList}'
                   :action='api' :headers='headers' :file-list='fileList' :limit='limit' :accept='accept' :multiple='multiple' :list-type='listType' :disabled='disabled'
                   :on-preview='handlePictureCardPreview' :on-remove='handleRemove' :before-upload='checkImage' :on-change="uploadChange" :on-exceed="checkExceed"
                   :on-success='uploadSuccess' :on-error='uploadFail'>
          <i class='el-icon-plus' v-if='listType == "picture-card"'></i>
          <el-button type='primary' v-else>{{ text }}</el-button>
        </el-upload>
      </div>
    </template>
    
    <script>
    import {mapActions} from 'vuex'
    import {loadPreviewPlugin, previewImage} from 'utils'
    import {isArrayFn} from 'utils/variable'
    export default {
      props: {
        disabled: {
          type:Boolean,
          default:false,
        },
        isUpdateUrl: {
          type: Boolean,
          default: false,
        },
        value: {
          type: String | Array,
          default: () => [],
        },
        url: {
          type: String | Array,
          default: () => [],
        },
        type: {
          type: String,
          default: 'image',
        },
        unClick: {
          type: Boolean,
          default: false,
        },
        isLyc: {
          type: Boolean,
          default: false,
        },
        multiple: {
          type: Boolean,
          default: false,
        },
        isHidedList: {
          type: Boolean,
          default: true,
        },
        richText: {
          type: Boolean,
          default: false,
        },
        isClear: {
          type: Boolean,
          default: false,
        },
        accept: {
          type: String,
          default: 'image/*',
        },
        size: {
          type: [Number,String],
          default: 1024, // 默认1024kb,即:1M;
        },
        text: {
          type: String,
          default: '选择图片',
        },
        limit: {
          type: Number,
          default: 1,
        },
        listType: {
          type: String,
          default: 'picture-card'
        },
        imageSize: {
          type: String,
          default: '',
        },
        imgType:{
          type:String,
          default:'book:cover'
        }
      },
      data () {
        return {
          urlClone: this.value,
          fileList: [],
          headers: {'X-HB-Client-Type': 'shop-pc',},
          loading: false,
          excelData: {
            header: null,
            results: null
          }
        }
      },
      watch: {
        value (nVal, oVal) {
          // 监听父组件清空url的时候清空文件
          if (nVal) return
          this.clearFiles()
        },
        isUpdateUrl (nVal, oVal) {
          // 弹框或tab切换类型不触发beforeMount,用该方式更新urlClone
          if (!nVal) return
          this.initFieldList()
        },
      },
      computed: {
        hideUploadList () {
          return this.multiple && this.isHidedList
        },
        api () {
          if(this.type == 'image') { // 图片
            return '/restcollege/collegeadmin/v1/upload/images'
          } else if (this.type == 'text' || this.type == 'xls') { // excel
            return '/restcollege/collegeadmin/v1/upload/lyric'
          } else if (this.type == 'audio') { // 音频
            return '/restcollege/collegeadmin/v1/upload/audio'
          } else if (this.type == 'bnl') { // 点读包:上传类型为'bnl', 'zip', 'rar', 'tar'
            return '/restcollege/collegeadmin/v1/upload/bookbnl'
          }else if (this.type=='bookImage'){   //小彼恩图片
            this.headers={'X-HB-Client-Type': 'xiaobien-pc',}
            return `/xiaobienapi/common/v1/upload/images/?imgType=${this.imgType}`
          }
        },
        isShowHasClass () {
          // 多张不去掉上传按钮
          if (this.multiple) return false
          // 单张判断是否已生成url
          if (!this.value) return false
          return this.value.length || this.urlClone.length
        },
      },
      methods: {
        ...mapActions(['uploadFile']),
        getImageList (fileList) {
          return fileList.map(item => {
            if (item.status != 'success') return ''
            if (item.response) { // 新上传的图
              return item.response.path
            } else { // 以前上传的图
              return item.url
            }
          })
        },
        clearFiles () {
          this.$refs.upload.clearFiles()
        },
        handleRemove (file, fileList) {
          let imagePathList = []
          fileList.map((item, index) => {
            if (item.uid == file.uid) {
              fileList.splice(index, 1)
            }
          })
          imagePathList = this.getImageList(fileList)
          this.urlClone = []
          this.$emit('update:value', imagePathList)
          // 嵌套多层的情况手动更新数据
          this.$emit('removeChange', imagePathList)
        },
        handlePictureCardPreview (file) {
          // 图片预览
          if(this.unClick || this.type != 'image' && this.type != 'bookImage') return
          previewImage(file.path || file.url)
          return false
        },
        uploadChange (e) {
          this.$emit('uploadChange', e)
        },
        uploadFail (err, file, fileList) {
          this.$message.error(`${JSON.parse(err.message).message},请重新上传`)
        },
        uploadSuccess (response, file, fileList) {
          // 音频类
          if (this.type == 'audio') {
            if (response.size > this.size ) {
              this.$message.error(`音频不能超过${this.size}M`)
              return
            }
            this.$emit('update:value', {...response, name: file.name.split('.mp3')[0]})
            return
          }
          // 富文本类
          if(this.richText) {
            this.$emit('asyncData', fileList)
            return
          }
          // excel类
          if(this.type == 'xls') {
            this.$emit('update:value', response.path)
            this.upload(file.raw)
            return
          }
          if (this.type == 'image' ||this.type=='bookImage') {
            // 图片类
            let imageList = this.getImageList(fileList)
            let imagePath
            if (fileList.length == 1) {
              // 单张直接返回图片地址
              imagePath = imageList[0]
            } else {
              // 多张返回图片地址列表
              imagePath = imageList
            }
            this.$emit('update:value', imagePath)
          }
          // 歌词文件
          if (this.type == 'text') {
            this.$emit('update:value', response.path)
          }
          // // 点读包文件
          // if (this.type == 'bnl') {
          //   this.$emit('update:value', response.path)
          //   this.$emit('update:size', response.size)
          // }
        },
        checkExceed (files, fileList) {
          this.$message.error(`最多只能上传${this.limit}张`)
        },
        checkImage (file) {
          let _this = this
          //普通的判断可以用return false
          // 获取文件尺寸,判断尺寸在不在规定范围之内
          if(this.isLyc) {
            if(file.name.split('.')[1].toLowerCase() != 'lrc') {
              this.$message.error('请上传格式正确的歌词文件')
              return false
            }
          }
          if (!_this.imageSize) {
            return true
          }
          return new Promise(function(resolve, reject) {
            let reader = new FileReader()
            let size = JSON.parse(_this.imageSize)
            reader.readAsDataURL(file)
            reader.onload = function(theFile) {
              let image = new Image()
              image.src = theFile.target.result
              image.onload = function() {
                if (file.size > _this.size * 1024 ) {
                  _this.$message.error(`${file.name}大小不对,请重新上传!`)
                  reject('图片大小不对')
                  return
                }
                if(size.width && size.height) {
                  const noSizeLimit = !this.height || !this.width
                  const rightSize = size.width == this.width && size.height == this.height
                  if (noSizeLimit || rightSize) {
                    file.width = size.width
                    file.height = size.height
                    resolve(file)
                    return
                  } else {
                    _this.$message.error(`${file.name}尺寸不对,请重新上传!`)
                    reject('图片尺寸不对')
                    return
                  }
                }
    
                if(!size.width || !size.height) {
                  if(size.width) {
                    if(size.width == this.width) {
                      file.width = size.width
                      resolve(file)
                    } else {
                      _this.$message.error(`${file.name}尺寸不对,请重新上传!`)
                      reject('图片尺寸不对')
                    }
                  } else {
                    if(size.height == this.height) {
                      file.height = size.height
                      resolve(file)
                    } else {
                      _this.$message.error(`${file.name}尺寸不对,请重新上传!`)
                      reject('图片尺寸不对')
                    }
                  }
                }
              }
            }
          })
        },
        generateData({ header, results }) {
          this.excelData.header = header
          this.excelData.results = results
          this.$emit('uploaded', results)
          // this.onSuccess && this.onSuccess(this.excelData)
        },
        handleDrop(e) {
          e.stopPropagation()
          e.preventDefault()
          if (this.loading) return
          const files = e.dataTransfer.files
          if (files.length !== 1) {
            this.$message.error('Only support uploading one file!')
            return
          }
          const rawFile = files[0] // only use files[0]
    
          if (!this.isExcel(rawFile)) {
            this.$message.error('Only supports upload .xlsx, .xls, .csv suffix files')
            return false
          }
          this.upload(rawFile)
          e.stopPropagation()
          e.preventDefault()
        },
        handleDragover(e) {
          e.stopPropagation()
          e.preventDefault()
          e.dataTransfer.dropEffect = 'copy'
        },
        handleUpload() {
          this.$refs['excel-upload-input'].click()
        },
        handleClick(e) {
          const files = e.target.files
          const rawFile = files[0] // only use files[0]
          if (!rawFile) return
          this.upload(rawFile)
        },
        upload(rawFile) {
          if (!this.beforeUpload) {
            this.readerData(rawFile)
            return
          }
          const before = this.beforeUpload(rawFile)
          if (before) {
            this.readerData(rawFile)
          }
        },
        readerData(rawFile) {
          this.loading = true
          return new Promise((resolve, reject) => {
            const reader = new FileReader()
            reader.onload = e => {
              const data = e.target.result
              const workbook = XLSX.read(data, { type: 'array' })
              const firstSheetName = workbook.SheetNames[0]
              const worksheet = workbook.Sheets[firstSheetName]
              const header = this.getHeaderRow(worksheet)
              const results = XLSX.utils.sheet_to_json(worksheet)
              this.generateData({ header, results })
              this.loading = false
              resolve()
            }
            reader.readAsArrayBuffer(rawFile)
          })
        },
        getHeaderRow(sheet) {
          const headers = []
          const range = XLSX.utils.decode_range(sheet['!ref'])
          let C
          const R = range.s.r
          /* start in the first row */
          for (C = range.s.c; C <= range.e.c; ++C) { /* walk every column in the range */
            const cell = sheet[XLSX.utils.encode_cell({ c: C, r: R })]
            /* find the cell in the first row */
            let hdr = 'UNKNOWN ' + C // <-- replace with your desired default
            if (cell && cell.t) hdr = XLSX.utils.format_cell(cell)
            headers.push(hdr)
          }
          return headers
        },
        isExcel(file) {
          return /\.(xlsx|xls|csv)$/.test(file.name)
        },
        initFieldList () {
          // 传入的 value 的值为空或者为数组时获取原格式
          // 传入的 value 为单张且有值时将string转为array格式
          this.urlClone = (isArrayFn(this.value) || !this.value) ? this.value : [this.value]
          // 已有图片的情况下初始化照片墙列表
          if (this.urlClone && this.urlClone.length) {
            this.fileList = this.urlClone.map(item => {
              return {
                name: item.name || item.audio_name || item,
                url: item,
              }
            })
          }
        },
      },
      beforeMount () {
        loadPreviewPlugin()
        this.initFieldList()
      },
    }
    </script>
    
    <style lang='less' scoped>
    .has {
      margin-top: -3px;
      :global(.el-upload--picture-card) {
        display: none;
      }
      :global(.el-upload--) {
        display: none;
      }
    }
    .unshow {
      :global(.el-upload-list--) {
        display: none;
      }
      :global(.el-upload-list--picture) {
        display: none;
      }
    }
    </style>
    

    相关文章

      网友评论

          本文标题:vue+element 实现和后端交互的上传文件功能

          本文链接:https://www.haomeiwen.com/subject/dwwrpltx.html