Vue2移动端(H5项目)项目基于vant封装图片上传组件(支持批量上传、单个上传、回显、删除、预览、最大上传数等功能)

430 阅读2分钟

一、最终效果

在这里插入图片描述

二、参数配置

1、代码示例:

<t-upload
   @fileList="fileList"
    :showFileList="showFileList"
    @showFile="showFile"
    :showFileUrl="showFileUrl"
  />

2、配置参数(TUpload Attributes)继承van-uploader的属性

参数说明类型默认值
limitSize限制上传文件大小Number10MB
fileType限制上传的文件类型String.jpg,.jpeg,.png
totalLimit最多上传个数限制Number5
showFileList回显文件的list(内含:url-->对应完整路径)Array-
showFileUrl上传组件回显图片--相对路径数据(后台需要)Array-
savePath服务器上传地址String自己的上传地址

3、events 事件继承van-uploader的事件

事件名说明返回值
fileList上传成功或删除成功触发返回最终上传数据
showFile回显list删除后触发返回回显上传没有删除的数据

三、具体页面使用

<template>
  <div class="initial_Judgment">
    <div class="img_box">
        <div class="img_title">
          终判图
        </div>
        <t-upload
          :showFileUrl="showFileUrl"
          :showFileList="showFileList"
          @fileList="fileList"
          @showFile="showFile"
        />
      </div>
  </div>
</template>
<script>
export default {
  name: 'initialJudgment',
  data() {
    return {
      formData: {
        images: [], //上传图片
      },
      showFileList: [], // 上传组件--回显内含url且是完整地址
      showFileUrl: [], // 上传组件回显图片--相对路径数据
    }
  },
  created() {
    this.getFinalInfo()
  },
  methods: {
    // 获取详情信息
    async getFinalInfo() {
      const res = await this.$api.getFinalInfo(this.$route.query.id)
      console.log('详情数据', res)
      if (res.success) {
        if (res.data.finalImages.length > 0) {
          this.showFileList = res.data.finalImages || []
          this.showFileUrl = res.data.finalImages.map(item => item.relativeUrl)
        }
      }
    },
    // 回显数据删除触发
    showFile(list) {
      this.showFileUrl = list
    },
    // 上传成功或删除触发
    fileList(list) {
      this.formData.images = list
    },
    // 点击确认
    async handlerConfirm() {
      const { warehouseSpaceId, receveMethod, images } = this.formData;
      const requiredFields = [
        { field: warehouseSpaceId, message: '请先选择卸货料垛' },
        { field: receveMethod, message: '请先选择收货方式' },
        { field: images.length || this.showFileUrl.length, message: '请先上传图片' }
      ];
      const hasEmptyFields = requiredFields.some(field => !field.field);
      if (hasEmptyFields) {
        this.$toast(requiredFields.find(field => !field.field).message);
        return;
      }
      let params = {
        ...this.formData,
      }
      params.images = [...this.showFileUrl, ...this.formData.images]
      console.log('最终参数---图片相对路径', params.images)
      // console.log('最终参数---', params)
      // return
      this.$dialog
        .confirm({
          message: '是否确认终判?'
        })
        .then(async () => {
          const res = await this.$api.finalConfirm(params)
          if (res.success) {
            this.$toast.success('确认成功')
            this.$router.push({ path: '/endJudgingScrapSteel' })
          }
        })
        .catch(() => {
          console.log('取消')
        })
    }
  },
};
</script>

四、源码

<template>
  <van-uploader
    class="t-upload"
    v-model="fileList"
    v-bind="uploadAttrs"
    v-on="$listeners"
    :before-read="beforeRead"
    :before-delete="delImg"
    :after-read="afterRead"
  />
</template>

<script>
import axios from 'axios'
import { getToken } from '@/utils/auth'
export default {
  name: 'TUpload',
  props: {
    // 限制上传文件大小默认10MB
    limitSize: {
      type: [Number, String],
      default: 10
    },
    // 限制上传的文件类型
    fileType: {
      type: String,
      default: '.jpg,.jpeg,.png'
    },
    // 最多上传个数限制
    totalLimit: {
      type: Number,
      default: 5
    },
    // 回显文件的list(内含:url-->对应完整路径)
    showFileList: {
      type: Array,
      default: () => {
        return []
      }
    },
    // 上传组件回显图片--相对路径数据
    showFileUrl: {
      type: Array,
      default: () => {
        return []
      }
    },
    // 服务器上传地址
    savePath: {
      type: String,
      default: `${process.env.VUE_APP_API_URL}/scmpda/file/upload`
    },
  },
  data() {
    return {
      fileList: [],
      fileUrls: [],
      showUrl: this.showFileUrl
    }
  },
  computed: {
    uploadAttrs() {
      return {
        'max-count': this.totalLimit,
        multiple: true,
        ...this.$attrs
      }
    }
  },
  watch: {
    showFileList: {
      handler(val) {
        this.fileList = val
      }
    },
    showFileUrl: {
      handler(val) {
        this.showUrl = val
      }
    }
  },
  methods: {
    beforeRead(file) {
      // console.log('上传前', file)
      if (file instanceof Array) {
        file.forEach(item => {
          const isNotMatchType = this.fileType.indexOf('.' + item.name.slice(item.name.lastIndexOf('.') + 1).toLocaleLowerCase()) === -1
          if (isNotMatchType) {
            this.$toast.fail('请上传jpg或png格式的图片')
            return false
          }
          const overSize = item.size / (1024 * 1024) > this.limitSize
          if (overSize) {
            this.$toast.fail(`上传文件不得大于${this.limitSize}MB`)
            return false
          }
        })
      } else {
        const isNotMatchType = this.fileType.indexOf('.' + file.name.slice(file.name.lastIndexOf('.') + 1).toLocaleLowerCase()) === -1
        if (isNotMatchType) {
          this.$toast.fail('请上传jpg或png格式的图片')
          return false
        }
        const overSize = file.size / (1024 * 1024) > this.limitSize
        if (overSize) {
          this.$toast.fail(`上传文件不得大于${this.limitSize}MB`)
          return false
        }
      }
      if (file.length >= this.totalLimit) {
        this.$toast.fail(`最多上传${this.totalLimit}个文件`)
        return false
      }
      return true
    },
    delImg(fileMsg) {
      const delIndex = this.fileList.findIndex(item => item === fileMsg);
      if (delIndex > -1) {
        this.fileList.splice(delIndex, 1);
        const showIndex = delIndex - this.showFileList.length;
        if (fileMsg.url) {
          this.showUrl.splice(showIndex, 1);
        } else {
          this.fileUrls.splice(showIndex, 1);
        }
      }
      this.$emit(fileMsg.url ? 'showFile' : 'fileList', fileMsg.url ? this.showUrl : this.fileUrls);
    },
    afterRead(file) {
      if (file instanceof Array) {
        file.forEach(f => {
          f.status = 'uploading'
          f.message = '上传中...'
          this.uploadFile(f)
        })
      } else {
        file.status = 'uploading'
        file.message = '上传中...'
        this.uploadFile(file)
      }
    },
    async uploadFile(file) {
      const formDataFile = new FormData()
      formDataFile.append('file', file.file)
      const res = await axios({
        url: this.savePath,
        method: 'post',
        headers: {
          'Content-Type': 'multipart/form-data',
          Authorization: getToken()
        },
        data: formDataFile
      })
      if (res.data.success) {
        file.status = 'done'
        file.message = '上传成功'
        this.fileUrls.push(res.data.data)
        this.$toast('图片上传成功!')
        this.$emit('fileList', this.fileUrls)
      } else {
        file.status = 'failed'
        file.message = '上传失败'
        this.$toast('照片上传失败,请重新上传!')
      }
    }
  }
}
</script>




相关文章

基于ElementUi再次封装基础组件文档


基于ant-design-vue再次封装基础组件文档


vue3+ts基于Element-plus再次封装基础组件文档