vantui上传组件自定义封装,图片上传前压缩,

本文展示了如何在Vue中创建一个用于图片上传和压缩的组件。组件使用了 vant 的Uploader组件,实现了图片预览、格式和大小校验、上传及删除功能。同时,文章还介绍了上传图片前的压缩方法,利用FileReader和canvas进行图片质量压缩,并确保图片大小不超过指定限制。
摘要由CSDN通过智能技术生成

一、新建NewUpload.vue文件


<template>
  <div class="multi_upload_box">
    <van-uploader
      :show-upload="showupload"
      :deletable="isdelect"
      v-model="extant"
      :after-read="afterRead"
      :name="uploadName"
      :multiple="multiple"
      :max-count="maxLen"
      :before-delete="deleteImgList"
      :before-read="beforeRead"
      accept=""
      :disabled="isdisabled"
    >
      <van-button v-if="uploadtype == 2" type="info">去上传</van-button>
    </van-uploader>
  </div>
</template>
<script>
import { upLoaderImg } from '@/utils/upload.js'
import { imgPreview } from "@/utils/imgPreview.js";
export default {
  name: 'NewUpload',
  props: {
    extantFiles: {//反馈到父组件的列表
      type: Array,
      default: function () {
        return []
      }
    },
    maxLen: {
      type: Number,
      default: 6
    },
    type: {
      type: String,
      default: ''
    },
    multiple: {
      type: Boolean,
      default: true
    },
    uploadName: {
      type: String,
      default: ''
    },
    isdelect: {
      type: Boolean,
      default: true
    },
    showupload: {
      type: Boolean,
      default: true
    },
    acceptype: {
      type: String,
      default: ''
    },
    fileType: {
      type: Array,
      default: () => ['png', 'jpg', 'jpeg'],
    },
    fileSize: {
      type: Number,
      default: 2,
    },
    uploadtype: {
      type: Number,
      default: 1
    },
    isdisabled: {
      type: Boolean,
      default: false
    }
  },
  computed: {

  },
  data() {
    return {
      extant: [],
      vueFile: {},
      imgList: [],
      count: 0
    }
  },
  watch: {
    'extantFiles': {
      handler: function (val) {
        this.showlist(val)
      },
      immediate: true,
      deep: true
    },
    'extant': {
      handler: function (val) {
        this.getlist(val)
      },
      immediate: true,
      deep: true
    },
  },
  methods: {
    beforeRead(file) {
      //图片上传之前校验类型
      this.count = this.extant.length;
      // 校验图片上传的格式
      // let fileType = '';
      // if (file instanceof Array && file.length) {
      //   for (let i = 0; i < file.length; i++) {
      //     fileType = file[i].type.substr(0, file[i].type.indexOf('/'));
      //     console.log(999, fileType)
      //     if (fileType !== 'image') {
      //       this.$toast.fail('格式错误')
      //       return false;
      //     }
      //   }
      // } else {
      //   fileType = file.type.substr(0, file.type.indexOf('/'));
      //   console.log(888, fileType)
      //   if (fileType !== 'image') {
      //     this.$toast.fail('格式错误')
      //     return false;
      //   }
      // }
      if (file instanceof Array && file.length) {
        for (let i = 0; i < file.length; i++) {
          const isTypeOk = this.fileType.some((item) => {
            let fileExtension = "";
            if (file[i].name.lastIndexOf(".") > -1) {
              fileExtension = file[i].name.slice(file[i].name.lastIndexOf(".") + 1);
            }
            // if (file[i].type.indexOf(item) > -1) return true;
            if (fileExtension && fileExtension.indexOf(item) > -1) return true;
            return false;
          });
          if (!isTypeOk && file) {
            this.$toast.fail(`文件格式不正确, 请上传${this.fileType.join("/")}格式文件!`);
            return false;
          }
          // if (this.fileSize && file) {
          //   const isLt = file[i].size / 1024 / 1024 < this.fileSize;
          //   if (!isLt) {
          //     this.$toast.fail(`上传文件大小不能超过 ${this.fileSize} MB!`);
          //     return false;
          //   }
          // }
        }
      } else {
        if (this.fileType && file) {
          const isTypeOk = this.fileType.some((item) => {
            let fileExtension = "";
            if (file.name.lastIndexOf(".") > -1) {
              fileExtension = file.name.slice(file.name.lastIndexOf(".") + 1);
            }
            console.log('22', file.type)
            // if (file.type.indexOf(item) > -1) return true;
            if (fileExtension && fileExtension.indexOf(item) > -1) return true;
            return false;
          });
          if (!isTypeOk && file) {
            this.$toast.fail(`文件格式不正确, 请上传${this.fileType.join("/")}格式文件!`);
            return false;
          }
        }
        // if (this.fileSize && file) {
        //   const isLt = file.size / 1024 / 1024 < this.fileSize;
        //   if (!isLt) {
        //     this.$toast.fail(`上传文件大小不能超过 ${this.fileSize} MB!`);
        //     return false;
        //     }
        // }
      }
      return true;
    },
    afterRead(file) {
      this.imgList = []
      if (Array.isArray(file)) {
        // 多图
        this.imgList = file
        // this.$emit('imgList', this.imgList)
        this.imgList.forEach((item) => {
          item.loading = false
        }) // 为了校验图片是否上传成功
        for (let index = 0; index < file.length; index++) {
          this.postImg(file[index], this.count + index, index)
        }
      } else {
        // 单图
        this.imgList.push(file)
        this.imgList.forEach((item) => {
          item.loading = false
        })  // 为了校验图片是否上传成功
        // this.$emit('imgList', this.imgList)
        // let index = 0
        this.postImg(file, this.count, 0)
      }
    },
    async postImg(file, index, item) {
      file.status = 'uploading'
      file.message = '上传中...'
      await imgPreview(file.file, async (obj) => {
        var that = this;
        const data = obj
        var newData = new FormData()
        newData.append('file', data)
        await upLoaderImg(newData).then(
          (resp) => {
            if (resp.code === 0) {
              this.$toast.success('上传成功')
              console.log('9955', resp)
              // that.extant[index].href = resp
              this.$set(that.extant[index], 'url', resp.payload.imgUrl) //这个可以是域名拼接的链接
              // that.extant[index].url = resp.payload.imgUrl //这个可以是域名拼接的链接
              this.$set(that.imgList[item], 'loading', true)
              // that.imgList[item].loading = true;
              if (that.imgList.length > 0) {
                file.status = ''
                file.message = ''
              }
            } else {
              that.$toast.fail(resp.errorMessage)
            }
          },
          (error) => {
            console.log('err', error)
            file.status = 'failed'
            file.message = '上传失败'
            for (var i = 0; i < this.extant.length; i++) {
              if (this.extant[i].file.name === obj.name) {
                this.extant.splice(i, 1) // 上传失败后清除正在上传的图片
              }
            }
          }
        )
      })
    },
    deleteImgList(file) {
      for (var i = 0; i < this.extant.length; i++) {
        if (this.extant[i].url === file.url) {
          this.extant.splice(i, 1)
        }
      }
    },
    getlist(val) {
      // console.log('我是监听', val)
      var list = []
      for (let i = 0; i < val.length; i++) {
        // this.extant[i].url = this.extant[i].fileUrl
        list.push({
          url: val[i].url,
          // href: val[i].href,
          // title: val[i].file.name,
          isImage: true //加上这个解决图片不显示的问题
        })
      }
      // this.$emit('update:extantFiles', list)
      this.$emit('change', list)
    },
    //从父组件拿需要渲染的图片列表
    showlist(val) {
      var newslist = val;//传进来图片值
      var oldlist = this.extant;//当前页面的图片值
      if (newslist.length != oldlist.length) {
        this.extant = val
      } else {
        // 长度相等且不为空
        var iscommon = true;
        // console.log('监听过来的',this.extant)
        // console.log('监听2222',val)
        if (this.extant.length > 0) {
          for (var i = 0; i < this.extant.length; i++) {
            if ((val[i].url != this.extant[i].url) && val[i].url && this.extant[i].url) {
              // console.log('qqqq',val[i].url)
              // console.log('ooooo',this.extant[i])
              iscommon = false
              break;
            }
          }
          if (!iscommon) {
            this.extant = val
          }
        }
      }
    }
  }
}
</script>
<style lang="less" scoped>
.imgshow {
  display: flex;
  flex-wrap: wrap;
  margin-top: 40px;
  background: pink;
}
.imgshow li {
  width: 100px;
}
.imgshow li img {
  display: block;
  width: 100%;
}
.multi_upload_box {
  ::v-deep .van-uploader__wrapper {
    justify-content: flex-start;
    .van-uploader__preview {
      margin-right: 24px;
      border-radius: 4px;
      border: 0.5px solid #eee;
      box-sizing: border-box;
    }
  }
}
</style>

二、新建upload.js文件,imgPreview.js图片压缩文件

// upload.js文件
import axios from 'axios'		//引入axios
import { Toast } from 'vant'	//引入Toast

export function upLoaderImg(file) {	//file为 你读取成功的回调文件信息
  let config = {
    headers: { //添加请求头
      'Content-Type': 'multipart/form-data'
    }
  }
  return new Promise((resolve, reject) => {
    axios.post(`/api/common/upload`, file,
      config).then(res => {
        resolve(res.data)
      }).catch(err => {
        Toast.fail('系统异常')
        reject(err)
      });
  })
}

export function formatter(time) {
  let nowdata = time == null ? new Date() : new Date(time);
  let year = nowdata.getFullYear();
  let month = nowdata.getMonth() + 1;
  let date = nowdata.getDate();
  let nowtime = year + "-";
  if (month < 10) {
    nowtime += "0";
  }
  nowtime += month + "-";
  if (date < 10) {
    nowtime += "0";
  }
  nowtime += date;

  return nowtime;
}

// 图片压缩
export const imgPreview = (file, callback) => {
  //将base64转换为文件
  function dataURLtoFile(dataurl, file) {
    var arr = dataurl.split(","),
      bstr = atob(arr[1]),
      n = bstr.length,
      u8arr = new Uint8Array(n);
    while (n--) {
      u8arr[n] = bstr.charCodeAt(n);
    }
    return new File([u8arr], file.name, {
      type: file.type
    });
  }
  // 压缩图片
  function compress(img) {
    let canvas = document.createElement("canvas");
    let ctx = canvas.getContext("2d");
    //瓦片canvas
    let tCanvas = document.createElement("canvas");
    let tctx = tCanvas.getContext("2d");
    // let initSize = img.src.length;
    let width = img.width;
    let height = img.height;
    //如果图片大于四百万像素,计算压缩比并将大小压至400万以下
    let ratio;
    if ((ratio = (width * height) / 4000000) > 1) {
      // console.log("大于400万像素");
      ratio = Math.sqrt(ratio);
      width /= ratio;
      height /= ratio;
    } else {
      ratio = 1;
    }
    canvas.width = width;
    canvas.height = height;
    //    铺底色
    ctx.fillStyle = "#fff";
    ctx.fillRect(0, 0, canvas.width, canvas.height);
    //如果图片像素大于100万则使用瓦片绘制
    let count;
    if ((count = (width * height) / 1000000) > 1) {
      // console.log("超过100W像素");
      count = ~~(Math.sqrt(count) + 1); //计算要分成多少块瓦片
      //      计算每块瓦片的宽和高
      let nw = ~~(width / count);
      let nh = ~~(height / count);
      tCanvas.width = nw;
      tCanvas.height = nh;
      for (let i = 0; i < count; i++) {
        for (let j = 0; j < count; j++) {
          tctx.drawImage(
            img,
            i * nw * ratio,
            j * nh * ratio,
            nw * ratio,
            nh * ratio,
            0,
            0,
            nw,
            nh
          );
          ctx.drawImage(tCanvas, i * nw, j * nh, nw, nh);
        }
      }
    } else {
      ctx.drawImage(img, 0, 0, width, height);
    }
    //进行最小压缩
    let ndata = canvas.toDataURL("image/jpeg", 0.3);
    tCanvas.width = tCanvas.height = canvas.width = canvas.height = 0;
    return ndata;
  }
  // 看支持不支持FileReader
  if (!file || !window.FileReader) {
    return;
  }
  if (/^image/.test(file.type)) {
    // 创建一个reader
    let reader = new FileReader();
    // 将图片转成 base64 格式
    reader.readAsDataURL(file);
    // 读取成功后的回调
    reader.onloadend = function () {
      let result = this.result;
      let img = new Image();
      img.src = result;
      //判断图片是否大于500K,是就直接上传,反之压缩图片
      if (this.result.length <= 2000 * 1024) {
        // 上传图片
        let imageFile = dataURLtoFile(this.result, file);
        callback(imageFile);
      } else {
        img.onload = function () {
          let data = compress(img);
          // 上传图片
          let imageFile = dataURLtoFile(data, file);
          callback(imageFile);
        };
      }
    }
  } else {
    let reader = new FileReader();
    reader.readAsDataURL(file);
    reader.onloadend = function () {
      let result = this.result;
      let img = new Image();
      img.src = result;
      let imageFile = dataURLtoFile(this.result, file);
      callback(imageFile);
    }
  }
};

三、其他文件引用NewUpload组件

<template>
  <div id="checkOrder">
    <div class="infoSubAll">
      <van-form @submit="onSubmit" :label-width="110" :scroll-to-error="true">
        <div class="infoSubTop">
          <div class="infoSubOne">
            <div class="addLiAll">
              <div class="nameStyl">上传验收结果</div>
              <NewUpload
                :extantFiles="enterpriseList"
                :uploadName="'enterprisename'"
                :maxLen="6"
                :fileType="['jpg', 'png', 'jpeg']"
                @change="enterpriseChange"
              ></NewUpload>
              <div class="contBtnAll">
                <van-button
                  round
                  block
                  type="info"
                  native-type="submit"
                  :loading="subFlag"
                  loading-type="spinner"
                  >提交工单</van-button
                >
              </div>
            </div>
          </div>
        </div>
      </van-form>
    </div>
  </div>
</template>

<script>

import NewUpload from '@/components/NewUpload.vue'
export default {
  name: 'CheckOrder',
  data() {
    return {
      enterpriseList: [],//接收子组件传过来的值
      subInfo: {
        newPicArr: []
      },
    }
  },
  components: {
    NewUpload
  },
  mounted() {

  },
  methods: {
    enterpriseChange(value) {
      this.enterpriseList = value
      this.subInfo.newPicArr = []
      this.enterpriseList.forEach((item) => {
        this.subInfo.newPicArr.push(item.url)
      })
    },
    getSubmitSave() {
      const data = {
        checkResultUrls: this.subInfo.newPicArr.join(',')
      }
      this.subFlag = true
      checkSubmit(data).then(
        (resp) => {
          if (resp.code === 0) {
            this.showSub = true
            setTimeout(() => {
              this.$router.push({
                path: '/homePage'
              })
            }, 3000)
          } else {
            this.$toast.fail(resp.errorMessage)
          }
          this.subFlag = false
        },
        (error) => {
          this.subFlag = false
          this.$toast.fail(error)
        }
      )
    },
    onSubmit() {
      this.getSubmitSave()
    },
  },
}
</script>

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值