vue基于element封装图片上传组件示例

图片单个上传,支持放大

import imgUpload from '@/components/upload/imgUpload'; // 图片单个上传

<imgUpload
                  class="photoImage"
                  :showTage="DragUploadShowTag"
                  :picDesc="DragUploadpicDesc"
                  :imgUrl="photoId"
                  :isEdit="true"
                  :isDelect="true"
                  :imgMaxWidth="600"
                  :imgMaxHeight="800"
                  :imgMinWidth="50"
                  :imgMinHeight="50"
                  @handleSucess="handleSucess"
                  key="photoPath"
                  v-model="photoId"
                >
                </imgUpload>

handleSucess(response) { // 返回文件id ,response // ... 进行业务操作 }, handleRemove(response) { // 返回回调的response // ... 进行业务操作 }, 

 

已封装图片组件

<template>
  <div>
    <el-upload ref='upload' :id='ref' class='upload-demo' name='file' :style='bodySize' :disabled='formEdit' accept='.jpg,.jpeg,.png,.JPG,.JPEG,.png,.pdf,.PDF' drag :before-upload='beforeUpload'
      action='/fa-pro-fastdfs/file/uploadFile' :auto-upload='true' :show-file-list='false' :on-success='handleSucess' :on-error='handleError' :headers='improtHeader'>
      <div v-if='!showImg'>
        <i class='el-icon-upload' v-if='showTage'></i>
        <div class='el-upload__text' v-html='showTage'></div>
        <div class='el-upload__tip' slot='tip' v-html='picDesc'></div>
      </div>
      <div v-else class='imgBox'>
        <div class='img-option' v-if='bigImgShow' @mouseleave='mouseleaveHandle'>
          <div class='btn'>
            <i class='el-icon-zoom-in' @click.stop='imgClick' />
            <i class='el-icon-upload2' style='margin-left: 20px' @mouseenter='formEdit = false' @mouseleave='formEdit = true' v-if='isEdit' />
            <i v-if="isEdit && isDelect" class="el-icon-delete" @click="handleRemove" />
          </div>
        </div>
        <el-image @mouseenter='mouseenterHandle' z-index='2010' class='img' :src='imgShowUrl + imgFileId' :preview-src-list='[imgShowUrl + imgFileId]' ref='elImg' />
      </div>
    </el-upload>
  </div>
</template>
<script>
import { accMul } from '@/util/util';
import { delFile } from '@/views/admin/api/fastdfs';

export default {
  name: 'imgUpload',
  props: {
    isEdit: {
      type: Boolean,
      default: true,
    },
    isDelect: {
      type: Boolean,
      default: false,
    },
    fileID: {
      type: String,
      default: '',
    },
    showTage: {
      type: String,
      default: () => `将文件拖到此处,或<em>点击上传</em>`,
    },
    //当前行信息
    rows: {
      type: Object,
      default: () => {},
    },
    // 图片url
    value: {
      type: String,
      default: '',
    },
    // 图片url
    imgUrl: {
      type: String,
      default: '',
    },
    // formEdit: {
    //   // 是否可上传
    //   type: Boolean,
    //   default: true
    // },
    imgMinWidth: {
      // 允许上传的图片最小宽度
      type: Number,
      default: 200,
    },
    imgMinHeight: {
      // 允许上传的图片最小高度
      type: Number,
      default: 200,
    },
    imgMaxWidth: {
      // 允许上传的图片最大宽度
      type: Number,
      default: 2000,
    },
    imgMaxHeight: {
      // 允许上传的图片最大高度
      type: Number,
      default: 2000,
    },
    picDesc: {
      // 图片上传要求说明
      type: String,
      default: '',
    },
  },
  data() {
    return {
      loading: true, //图片压缩等待
      formEdit: false,
      ref: 'dragUpload' + +Math.floor(Math.random() * 9999999999999999), // 避免使用时混乱,取随机数值
      showImg: false,
      imgShowUrl:
        '/fa-pro-fastdfs/file/downloadImage?access_token=' +
        this.$store.getters.access_token +
        '&id=',
      improtHeader: {
        'Content-Type': 'multipart/form-data; boundary=;',
        Authorization: 'Bearer ' + this.$store.getters.access_token,
      },
      tempImgId: '',
      bodySize: {
        width: 428,
        height: 270,
      },
      dialogVisible: false,
      bigImgShow: false,
    };
  },
  computed: {
    imgId: {
      get() {
        return this.imgUrl;
      },
      set(val) {
        //this.imgFileId = val;
      },
    },
    imgFileId: {
      get() {
        if (this.imgUrl) {
          return this.imgUrl;
        } else {
          return this.tempImgId;
        }
      },
      set(val) {},
    },
  },
  watch: {
    imgId(val) {
      if (val !== '' || val !== null) {
        this.imgFileId = val;
        this.showImg = true;
      }
      if (val === '' || val === null) {
        this.showImg = false;
      }
    },
  },
  created() {
    if (this.imgUrl !== '' || this.imgUrl !== null) {
      this.showImg = true;
    }
    if (this.imgUrl === '' || this.imgUrl === null) {
      this.showImg = false;
    }
  },
  mounted() {
    this.init();
  },
  methods: {
    mouseleaveHandle(e) {
      this.bigImgShow = false;
      this.formEdit = false;
    },
    mouseenterHandle(e) {
      this.bigImgShow = true;
      this.formEdit = true;
    },
    upload() {
      this.formEdit = false;
    },
    init() {
      this.$nextTick(() => {
        let node = document.getElementById(this.ref).childNodes[0]
          .childNodes[0];
        node.style.height = accMul(0.63, node.offsetWidth) + 'px';
      });
    },
    imgClick() {
      this.$refs.elImg.clickHandler();
      this.bigImgShow = false;
      this.formEdit = true;
    },
    //上传验证
    // beforeUpload(file) {
    //   // 设置允许上传的文件格式
    //   let uploadExtend = ['jpg', 'jpeg', 'png', 'JPG', 'JPEG', 'png'];
    //   // 获取当前上传文件后缀名并转为小写
    //   let suffix = file.name
    //     .substr(file.name.lastIndexOf('.'))
    //     .substr(1)
    //     .toLowerCase();
    //   // 上传文件类型校验
    //   if (!uploadExtend.includes(suffix)) {
    //     this.$notify({
    //       title: '提示',
    //       dangerouslyUseHTMLString: true,
    //       type: 'warning',
    //       message: `<p>文件格式不正确,请上传jpg,jpeg,png,JPG,JPEG,png格式的文件</p>`
    //     });
    //     return false;
    //   }
    //   // 获取允许上传的文件大小 并由MB转为B
    //   let _size = 3; // 默认1MB
    //   let docSize = parseFloat(_size) * 1024 * 1024;
    //   // 上传文件大小校验
    //   if (file.size > docSize) {
    //     this.$notify({
    //       title: '提示',
    //       dangerouslyUseHTMLString: true,
    //       type: 'warning',
    //       message: `<p>文件大小过大,请上传${_size}MB以内大小的文件</p>`
    //     });
    //     return false;
    //   }
    //   // 校验上传图片的尺寸
    //   const isSize = new Promise((resolve, reject) => {
    //     let minWidth = this.imgMinWidth; // 允许上传的最小宽度
    //     let minHeight = this.imgMinHeight; // 允许上传的最小宽度
    //     let maxWidth = this.imgMaxWidth; // 允许上传的最大宽度
    //     let maxHeight = this.imgMaxHeight; // 允许上传的最大高度
    //     let _URL = window.URL || window.webkitURL;
    //     let img = new Image();
    //     img.onload = function() {
    //       let valid =
    //         img.width >= minWidth &&
    //         img.width <= maxWidth &&
    //         img.height >= minHeight &&
    //         img.height <= maxHeight;
    //       valid ? resolve() : reject();
    //     };
    //     img.src = _URL.createObjectURL(file);
    //   }).then(
    //     () => {
    //       return file;
    //     },
    //     () => {
    //       this.$notify({
    //         title: '提示',
    //         dangerouslyUseHTMLString: true,
    //         type: 'warning',
    //         message: `<p>请上传图片宽度在${this.imgMinWidth}像素-${this.imgMaxWidth}像素,高度在${this.imgMinHeight}像素-${this.imgMaxHeight}像素范围内的照片!</p>`
    //       });
    //       return Promise.reject();
    //     }
    //   );
    //   return isSize;
    // },
    //上传成功
    handleSucess(response, file, fileList) {
      if (response.code === 0) {
        this.imgFileId = response.data.fileId;
        this.tempImgId = response.data.fileId;
        this.showImg = true;
        this.$emit('handleSucess', response.data.fileId);
        this.$notify({
          title: '成功',
          message: '上传成功',
          type: 'success',
        });
      }
    },
    //上传失败
    handleError(err, file, fileList) {
      this.$emit('handleError', err, file, fileList, this.rows);
      if (err.type === 'error') {
        this.$notify({
          title: '提示',
          message: '上传失败',
          type: 'error',
        });
      }
    },
    beforeUpload(file) {
      console.log(file);
      // 设置允许上传的文件格式
      let uploadExtend = ['jpg', 'jpeg', 'png', 'JPG', 'JPEG', 'png'];
      let suffix = file.name
        .substr(file.name.lastIndexOf('.'))
        .substr(1)
        .toLowerCase();
      // 上传文件类型校验
      if (!uploadExtend.includes(suffix)) {
        this.$notify({
          title: '提示',
          dangerouslyUseHTMLString: true,
          type: 'warning',
          message: `<p>文件格式不正确,请上传jpg,jpeg,png,JPG,JPEG,png格式的文件</p>`,
        });
        return false;
      }
      // 获取允许上传的文件大小 并由MB转为B
      const isIE = !!window.ActiveXObject || 'ActiveXObject' in window;
      let _size = isIE ? 5 : 20;
      let docSize = parseFloat(_size) * 1024 * 1024;
      // 上传文件大小校验
      if (file.size > docSize) {
        this.$notify({
          title: '提示',
          dangerouslyUseHTMLString: true,
          type: 'warning',
          message: `<p>文件大小过大,请上传${_size}MB以内大小的文件</p>`,
        });
        return false;
      }
      let _this = this;
      return new Promise((resolve, reject) => {
        let isLt2M = file.size / 1024 / 1024 < 10; // 判定图片大小是否小于10MB
        if (!isLt2M) {
          reject();
        }
        let image = new Image(),
          resultBlob = '';
        image.src = URL.createObjectURL(file);

        if (!isIE) {
          this.loading = this.$loading({
            lock: true,
            text: '图片压缩中请勿操作页面...',
            spinner: 'el-icon-loading',
            background: 'rgba(0, 0, 0, 0.7)',
          });
        }
        image.onload = () => {
          let minWidth = this.imgMinWidth; // 允许上传的最小宽度
          let minHeight = this.imgMinHeight; // 允许上传的最小宽度
          if (image.width < minWidth || image.height < minHeight) {
            this.$notify({
              title: '提示',
              dangerouslyUseHTMLString: true,
              type: 'warning',
              message: `<p>上传图片要求宽度大于${this.imgMinWidth}像素,高度大于${this.imgMinHeight}像素!</p>`,
            });
            reject();
          }
          if (docSize > 1 && !isIE) {
            this.loading = this.$loading({
              lock: true,
              text: '图片压缩中请勿操作页面...',
              spinner: 'el-icon-loading',
              background: 'rgba(0, 0, 0, 0.7)',
            });
            resultBlob = _this.compressUpload(image, file, 1);
          }

          // 调用方法获取blob格式,方法写在下边
          resolve(resultBlob);
        };
        image.onerror = () => {
          reject();
        };
      });
    },
    /* 图片压缩方法-canvas压缩 */
    compressUpload(image, file, size) {
      let canvas = document.createElement('canvas');
      let ctx = canvas.getContext('2d');
      let initSize = image.src.length;
      let { width } = image,
        { height } = image;
      canvas.width = width;
      canvas.height = height;
      ctx.fillRect(0, 0, canvas.width, canvas.height);
      ctx.drawImage(image, 0, 0, width, height);

      // 初始化压缩0.6
      let quality = 0.6;
      let compressData = canvas.toDataURL(file.type || 'image/jpeg', quality);
      console.log(compressData.length / (1024 * 1024));
      console.log(size);

      while (compressData.length / (1024 * 1024) > size) {
        quality -= 0.06;
        console.log(compressData.length / (1024 * 1024));
        compressData = canvas.toDataURL('image/jpeg', quality);
      }
      this.loading.close();
      console.log(this.loading);
      // 压缩后调用方法进行base64转Blob,方法写在下边
      let blobImg = this.dataURItoBlob(compressData);
      return blobImg;
    },

    /* base64转Blob对象 */
    dataURItoBlob(data) {
      let byteString;
      if (data.split(',')[0].indexOf('base64') >= 0) {
        byteString = atob(data.split(',')[1]);
      } else {
        byteString = unescape(data.split(',')[1]);
      }
      let mimeString = data.split(',')[0].split(':')[1].split(';')[0];
      let ia = new Uint8Array(byteString.length);
      for (let i = 0; i < byteString.length; i += 1) {
        ia[i] = byteString.charCodeAt(i);
      }
      return new Blob([ia], { type: mimeString });
    },
    // 删除
    handleRemove() {
      let fileId = this.fileID;
      if (!fileId) {
        return;
      }
      let data = {
        id: fileId,
      };
      delFile(data).then((res) => {
        if (res.code == 0) {
          this.showImg = false;
          this.$message.success('删除成功');
          this.$emit('handleRemove', this.list);
        } else {
          this.$message.error(res.msg);
        }
      });
    },
  },
};
</script>
<style lang='scss' scoped>
.imgBox {
  position: absolute;
  top: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;

  .img-option {
    z-index: 3;
    position: absolute;
    display: flex;
    width: 100%;
    height: 100%;
    background-color: rgba(0, 0, 0, 0.3);
    align-items: center;
    justify-content: center;
    top: 0px;

    .btn {
      color: #fff;
      font-size: 36px;
    }
  }

  .img {
    margin: 0 auto;
    display: block;
    max-width: 100%;
    max-height: 100%;
    width: 100%;
    height: 100%;
    // z-index: 2; // 20211002 by gcl edit 当一个页面使用多个imageUpload, 其他放大查看时,索引曾影响展示
  }
}

/deep/ .el-upload__tip {
  line-height: 18px !important;

  i {
    font-style: normal;
    color: red;
  }
}

/deep/ .el-image-viewer__wrapper {
  z-index: 4;
}

.big-img {
  //width: 60%;
  //height: 80%;
  /deep/ .el-dialog__body {
    display: flex;
    align-items: center;
    justify-content: center;
  }
}
</style>

 

//封装的工具类中accMul方法 

// 乘法:
export const accMul = function (arg1, arg2) {
    arg1 = arg1 ? arg1 : 0;
    arg2 = arg2 ? arg2 : 0;
    var m = 0,
        s1 = arg1.toString(),
        s2 = arg2.toString();
    try {
        m += s1.split(".")[1].length
    } catch (e) { }
    try {
        m += s2.split(".")[1].length
    } catch (e) { }
    return Number(s1.replace(".", "")) * Number(s2.replace(".", "")) / Math.pow(10, m)
}

 

 

 

效果如下,目前截图缺少删除按钮,支持上传更新、放大、删除

 

posted @ 2022-07-04 18:15  Gaochunling  阅读(209)  评论(0编辑  收藏  举报