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

一、最终效果

在这里插入图片描述

二、参数配置

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);
    },

    async afterRead(file) {
      const newFile = new FormData()
      if (file instanceof Array) {
        file.forEach(async f => {
          newFile.append("file", f.file)
          const res = await axios({
            url: this.savePath,
            method: 'post',
            headers: {
              'Content-Type': 'multipart/form-data',
              Authorization: getToken()
            },
            data: newFile
          })
          if (res.data.success) {
            this.fileUrls.push(res.data.data)
            this.$toast('图片上传成功!')
          }
        })
      } else {
        newFile.append('file', file.file)
        console.log('上传后', newFile)
        const res = await axios({
          url: this.savePath,
          method: 'post',
          headers: {
            'Content-Type': 'multipart/form-data',
            Authorization: getToken()
          },
          data: newFile
        })
        if (res.data.success) {
          this.fileUrls.push(res.data.data)
          this.$toast('图片上传成功!')
        }
      }
      this.$emit('fileList', this.fileUrls)
    }
  },

}
</script>



相关文章

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


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


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

  • 13
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wocwin

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值