uniapp开发手机端,全文件上传:图片,视频,文件(excel、pdf、word等)...

4,967 阅读2分钟

一、用户需求

安卓和ios,选择文件(excel、pdf、word等)并且上传

二、技术调查

使用dcloud插件市场里的【文件选择、文件上传组件(图片,视频,文件等)】插件

插件使用:

<!-- 也可以下载示例项目查看使用方法 -->
<template>
    <view>
        <button @click="handleUploadClick">上传</button>
        <xe-upload ref="XeUpload" :options="uploadOptions" @callback="handleUploadCallback"></xe-upload>
    </view>
</template>

<script>
export default {
    data() {
        return {
            uploadOptions: {
                // url: 'http://192.168.31.185:3000/api/upload', // 不传入上传地址则返回本地链接
            },
        };
    },
    methods: {
        handleUploadClick() {
            // 使用默认配置则不需要传入第二个参数
            // type: ['image', 'video', 'file'];
            this.$refs.XeUpload.upload('file', {});
            // this.$refs.XeUpload.upload('image', {
            //  count: 6,
            //  sizeType: ['original', 'compressed'],
            //  sourceType: ['album'],
            // });
        },
        handleUploadCallback(e) {
            // e.type: ['choose', 'success', 'warning']
            // choose 是options没有传入url,返回临时链接时触发
            // success 是上传成功返回对应的数据时触发
            // warning 上传或者选择文件失败触发
            // ......
        },
    },
};
</script>

三、效果图

image.png

ios端
image.png

安卓端
image.png

image.png

四、代码实现

<template>
  <view>
    <my-row v-if="label" type="detailTitle" :title="label" :required="required" :class="labelClass"></my-row>
    <view v-if="showTip" class="submit-form-tip mb-20" :class="tipClass">
      <view>{{ uploadFileTipPatternText }}</view>
      <view>{{ uploadFileTipSizeText }}</view>
    </view>
    <view class="my-upload-file mb-20" :class="fileBtnClass" @click="chooseFile">
      <image class="icon-size-32 mr-10" src="../../static/common/upload-outlined.png" mode=""></image>
      <text>上传文件</text>
    </view>
    <template v-if="isShowFileList">
      <template v-if="bindValue.length">
        <my-row type="4" :value="bindValue" :file-delete-icon="true" @fileDelete="fileDelete"></my-row>
      </template>
    </template>
    <xe-upload ref="XeUpload" :options="uploadOptions" @callback="handleUploadCallback"></xe-upload>
  </view>
</template>

<script>
import {
  fileAccept
} from '@/utils/commonFun.js'
import {
  batchUpload
} from '@/api/common.js'
export default {
  name: 'MyUploadFile',
  props: {
    value: {
      type: Array,
      default: () => []
    },
    required: {
      type: Boolean,
      default: false
    },
    // label
    label: {
      type: String,
      default: ''
    },
    // label类名
    labelClass: {
      type: String,
      default: ''
    },
    // 是否显示提示
    showTip: {
      type: Boolean,
      default: true
    },
    // 文件格式提示
    uploadFileTipPattern: {
      type: String,
      default: ''
    },
    // 文件限制提示
    uploadFileTipSize: {
      type: String,
      default: ''
    },
    // 文件格式
    accept: {
      type: Array,
      default: () => ([])
    },
    // 提示类名
    tipClass: {
      type: String,
      default: ''
    },
    // 是否显示文件列表
    isShowFileList: {
      type: Boolean,
      default: true
    },
    // 最大上传数量
    maxCount: [String, Number],
    // 文件大小
    fileSize: {
      type: Number,
      default: 20
    },
    fileBtnClass: {
      type: String,
      default: 'file-btn-wieth'
    },
    type: {
      default: 'file', // image, video, file
      type: String
    }
  },
  computed: {
    bindValue: {
      get() {
        return this.value
      },
      set(val) {
        this.$emit('input', val)
        this.$emit('change', val)
      }
    },
    uploadFileTipPatternText() {
      if (this.uploadFileTipPattern) {
        return this.uploadFileTipPattern
      }
      return `请上传"word/excel/pdf/图片/压缩包/文本"等格式文件`
    },
    uploadFileTipSizeText() {
      if (this.uploadFileTipSize) {
        return this.uploadFileTipSize
      }
      let text = `单个文件不超过${this.fileSize}MB`
      if (this.maxCount) {
        text += `,最多上传${this.maxCount}个`
      }
      return text
    },
    uploadFileAccept() {
      if (this.accept.length > 0) {
        return this.accept
      }
      return fileAccept
    }
  },
  data() {
    return {
      // uploadOptions 参数跟uni.uploadFile的参数是一样的(除了类型为Function的属性)
      uploadOptions: {}
    }
  },
  methods: {
    /**
     * 选择文件
     */
    chooseFile() {
      // App、H5 文件拓展名过滤 { extension: ['.doc', '.docx'] } 或者 { extension: '.doc, .docx' }
      this.$refs.XeUpload.upload(this.type)
    },
    /**
     * 选择文件 回调
     */
    handleUploadCallback(e) {
      if (['choose', 'success'].includes(e.type)) {
        const tmpFiles = (e.data || []).map(({ name, size, tempFilePath, fileType }) => {
          return {
            name: name,
            size: size,
            type: fileType,
            path: tempFilePath
          }
        })
        this.fileUpload(tmpFiles)
      }
    },
    /**
     * 文件上传
     * @param {Object} files
     */
    fileUpload(files) {
      let fileSuffixFlag = false
      let isFileSizeFlag = false
      // 判断数量
      if (this.maxCount !== undefined) {
        if (this.bindValue.length === 0 && files.length > Number(this.maxCount)) {
          uni.$u.toast(`最多上传${this.maxCount}个`)
          return
        }
        if (this.bindValue.length > 0 && this.bindValue.length >= Number(this.maxCount)) {
          uni.$u.toast(`最多上传${this.maxCount}个`)
          return
        }
      }
      files.forEach(item => {
        let fileSuffix = item.name.substring(item.name.lastIndexOf('.')).toLowerCase()
        let isFileSize = item.size / 1024 / 1024 < this.fileSize
        // 判断格式
        if (this.uploadFileAccept.indexOf(fileSuffix) === -1) {
          fileSuffixFlag = true
        }
        // 判断大小
        if (!isFileSize) {
          isFileSizeFlag = true
        }
      })
      // 判断格式
      if (fileSuffixFlag) {
        uni.$u.toast(`请上传“${this.uploadFileAccept.join('/').replace(/./g, '')}”等格式文件`)
        return
      }
      // 判断大小
      if (isFileSizeFlag) {
        uni.$u.toast(`文件大小不能超过 ${this.fileSize}MB!`)
        return
      }
      uni.showLoading({
        title: '上传中'
      })
      let temp = []
      files.forEach((item, index) => {
        temp.push({
          name: 'files' + index,
          uri: item.path
        })
      })
      batchUpload(temp).then(res => {
        res.forEach(item => {
          this.bindValue.push(item)
        })
      }).finally(_ => {
        uni.hideLoading()
      })
    },
    /**
     * 文件删除
     * @param {Object} data
     */
    fileDelete(data) {
      this.bindValue.splice(data.index, 1)
    }
  }
}
</script>

<style lang="scss" scoped>
.my-upload-file {
  height: 116rpx;
  border-radius: 20rpx;
  border: 2rpx solid #FFFFFF;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 500;
  color: #005AFF;
  box-sizing: border-box;
  &.file-btn-wieth {
    background: rgba(255, 255, 255, 0.3);
  }
  &.file-btn-blue {
    background: #EDF3FF;
  }
}
</style>
// 图片格式:jpg/jpeg/png/gif/bmp
export const imgAccept = ['.jpg', '.jpeg', '.png', '.gif', '.bmp']

// office格式:doc/docx/xls/xlsx/xlsm/pdf/ppt
export const officeAccept = ['.doc', '.docx', '.xls', '.xlsx', '.xlsm', '.pdf', '.ppt']

// zip格式:zip/tar/rar/7z
export const zipAccept = ['.zip', '.tar', '.rar', '.7z']

// txt格式:txt
export const txtAccept = ['.txt']

// 文件全格式:word/excel/pdf/图片/压缩包/文本
export const fileAccept = [
    ...officeAccept,
    ...imgAccept,
    ...zipAccept,
    ...txtAccept
]

五、参考

uniapp上传多个文件