使用 vue-upload 上传文件, 并进行压缩

<!-- 必须属性: visible, action, -->
<template>
    <div class="upload-container">
        <el-dialog v-loading="loading" :title="options.title" :visible.sync="options.visible" width="35%"
                   :before-close="beforeClose">
            <el-row style="text-align: center; height: 0.3rem">
                <b style="color: #f5222d;">上传完成前请勿关闭对话框</b>
            </el-row>

            <el-upload ref="fileUpload" drag :data="options.data" :headers="headers"
                       :multiple="true" list-type="picture" :file-list="fileList" :on-change="handleChange"
                       :auto-upload="false" :on-error="handleError"
                       :http-request="uploadFiles"
                       :on-exceed="handleExceed" :limit="options.limit" action="">
                <i class="el-icon-upload"/>
                <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
                <div class="el-upload__tip" slot="tip">只能上传图片文件,每个不超过5M, 一次最多上传{{options.limit}}个文件</div>
            </el-upload>
            <span slot="footer" class="dialog-footer">
                <el-button @click="beforeClose">取 消</el-button>
                <el-button type="primary" @click="submit()">确 定</el-button>
              </span>
        </el-dialog>
    </div>
</template>

<script>
  import {compress} from '@/utils/pictureUtils.js'

  export default {
    name: 'CustHouseFileUpload',
    props: {
      options: {
        title: '上传附件',
        visible: false,
        url: 'basicdata/houseCustAccessory/custFileDocUpload',
        //请求的额外参数
        data: {},
        limit: 5
      }

    },
    data() {
      return {
        fileList: [],
        loading: false,
        headers: this.getHeaders(),
        uploadSuccessFiles: [],
      }
    },
    mounted() {
    },
    methods: {
      //文件状态改变时的钩子,添加文件、上传成功和上传失败时都会被调用
      handleChange(file, files) {
        let temp = this.fileList.find(item => item.name === file.name);
        if (temp && files.length > this.fileList.length) {
          files.pop();
          this.$notify.warning({
            title: '提示',
            message: '文件重复,请重新选择',
            duration: 2000
          });
          return false;
        }
        this.fileList = [...files];

      },
      //文件超出个数限制时的钩子
      handleExceed(files, fileList) {
        this.$notify.warning({
          title: '提示',
          message: '以达到个数上限,请移除后再添加!',
          duration: 2000
        });
      },

      submit() {
        //判断上传文件,没有文件给出友好提示
        if (!this.fileList || !this.fileList.length) {
          this.$notify.error({
            title: '错误',
            message: '请选择上传的文件',
            duration: 2000
          });
          return;
        }
        this.fileList[0].status = 'ready';
        // this.$refs.fileUpload.submit();
        this.uploadFiles({file: this.fileList[0], data: this.options.data});
      },
      uploadFiles(param) {
        let _this = this;
        let formData = new FormData();
        formData.append('data', JSON.stringify(param.data));
        // 压缩后上传
        this.compressAvatard(param.file, 1024 * 3, function (res) {
          formData.append("files", res);
          _this.uploadFileRequest(_this.options.url, formData, data => {
            if (data && data.length > 0) {
              _this.$notify({
                title: '成功',
                message: '上传成功',
                type: 'success'
              });
            }
          });
        });
      },
      handleError(err, file, fileList) {
        let errJson = JSON.stringify(err);
        if (errJson && errJson.length > 50) {
          errJson = "上传失败";
        }
        //上传失败处理
        this.$notify.error({
          title: '失败',
          message: errJson,
          duration: 3000
        });
        console.error(errJson, err);
      },
      beforeClose() {
        this.fileList = [];
        this.$refs.fileUpload.clearFiles();
        this.uploadSuccessFiles = [];
        this.options.visible = false;
        //上传完成以后,调用父组件的方法进行刷新页面操作
        this.$emit('closeFile');
      },
      getHeaders() {
        return {
          authorization: this.$store.getters["login/principal"],
          token: this.$store.getters["login/token"],
          uploadUserId: this.$store.getters["login/userId"],
        }
      },
      //把图片文件作为参数传递到方法中
      compressAvatard(file, kb, callback) {
        let _this = this;
        let raw = file.raw? file.raw: file;
        compress(raw, function (val) {
          // val是Blob类型,转换为file类型
          let newfile = new window.File([val], file.name, {type: raw.type});
          newfile.uid = file.uid;
          // 压缩率过低则停止压缩, 防止死循环
          if ((newfile.size / 1024) > kb && (newfile.size / file.size < 0.9 ) ) {
            console.log("图片过大:" + newfile.size + ',已压缩');
            _this.compressAvatard(newfile, kb, callback);
          } else {
            callback(newfile);
            console.log("压缩后大小:" + newfile.size);
          }
        });

      },
    }
  }
</script>

<style scoped>
    .upload-container {
        width: auto;
    }
</style>

压缩工具类:  

/**
 * @日期 2020/12/9
 * @描述:
 */
// 调用示例
// import { compress } from '@/utils/pictureUtils.js'
// if( (file.size/1024/1024) > 5){
//   console.log("图片过大:" + file.size + ',已压缩');
//   compress(file.raw, function(val){
//     let newfile = new window.File([val], file.name, { type: file.raw.type });
//     newfile.uid = file.uid;
//     console.log("压缩后大小:" + newfile.size );
//   });
// }
/** 图片压缩,默认同比例压缩
  *  @param {Object} fileObj
  *  图片对象
  *  回调函数有一个参数,base64的字符串数据
  */
export function compress(fileObj, callback) {
  try {
    const image = new Image();
    image.src = URL.createObjectURL(fileObj);
    image.onload = function() {
      const that = this;
      // 默认按比例压缩
      let w = that.width;
      let h = that.height;
      const scale = w / h;
      w = fileObj.width || w;
      h = fileObj.height || (w / scale);
      let quality = 0.8; // 默认图片质量为0.7
      // 生成canvas
      const canvas = document.createElement('canvas');
      const ctx = canvas.getContext('2d');
      // 创建属性节点
      const anw = document.createAttribute('width');
      anw.nodeValue = w;
      const anh = document.createAttribute('height');
      anh.nodeValue = h;
      canvas.setAttributeNode(anw);
      canvas.setAttributeNode(anh);
      ctx.drawImage(that, 0, 0, w, h);
      // 图像质量
      if (fileObj.quality && fileObj.quality <= 1 && fileObj.quality > 0) {
        quality = fileObj.quality
      }
      // quality值越小,所绘制出的图像越模糊
      const data = canvas.toDataURL('image/jpeg', quality);
      // 压缩完成执行回调
      const newFile = convertBase64UrlToBlob(data);
      callback(newFile)
    }
  } catch (e) {
    console.error('压缩失败!', e)
  }
}
function convertBase64UrlToBlob(urlData) {
  const bytes = window.atob(urlData.split(',')[1]); // 去掉url的头,并转换为byte
  // 处理异常,将ascii码小于0的转换为大于0
  const ab = new ArrayBuffer(bytes.length);
  const ia = new Uint8Array(ab);
  for (let i = 0; i < bytes.length; i++) {
    ia[i] = bytes.charCodeAt(i)
  }
  return new Blob([ab], { type: 'image/png' })
}

 

Logo

前往低代码交流专区

更多推荐