Vue 图片压缩上传: element-ui + lrz

步骤

  • 安装依赖包 npm install --save lrz
  • main.js里引入 import lrz from 'lrz'
  • 封装 compress函数
  • 封装上传组件 upload-image
  • 在 vue 文件中 使用

封装 compress函数

// eslint-disable

/** @format */
// base64编码转File
export function dataURLtoFile(dataurl, filename) {
  var arr = dataurl.split(','),
    mime = arr[0].match(/:(.*?);/)[1],
    bstr = atob(arr[1]),
    n = bstr.length,
    u8arr = new Uint8Array(n);
  while (n--) {
    u8arr[n] = bstr.charCodeAt(n);
  }
  return new File([u8arr], filename, { type: mime });
}

// main function.
export function compress(file, fileList, that, reference) {
  if (file.status != 'ready') {
    return;
  }
  let index = reference.uploadFiles.indexOf(file);

  // jpg/jpeg/bmp/gif/png
  let isJPG =
    file.raw.type === 'image/jpg' ||
    file.raw.type === 'image/jpeg' ||
    file.raw.type === 'image/png' ||
    file.raw.type === 'image/gif' ||
    file.raw.type === 'image/bmp'

  const isLt20M = file.size / 1024 / 1024 < 20;
  if (!isJPG) {
    that.$message.error('不支持的格式,请上传jpg/jpeg/bmp/gif/png格式的图片!');
    fileList.splice(fileList.indexOf(file), 1);
    return;
  }
  if (!isLt20M) {
    that.$message.error('上传图片大小不能超过 20MB!');
    fileList.splice(fileList.indexOf(file), 1);
    return;
  }
  if (isJPG & isLt20M) {
    if (isLt2M(file)) {
      // pdf不压缩
      submit(reference, file);
    } else {
      let options = {};
      lrz(file.raw, options)
        .then(rst => {
          let tempFile = dataURLtoFile(rst.base64, rst.origin.name);
          tempFile.uid = rst.origin.uid;
          reference.uploadFiles[index].raw = tempFile;
          reference.uploadFiles[index].size = rst.fileLen;
        })
        .catch(function (error) {
          // 失败时执行
          if (error) {
            // IE报错
            if (error.name == 'TypeError' && error.message == '对象不支持此操作') {
              that.$message.error('当前浏览器不支持上传大于2M的文件,请更换浏览器!');
            }
            // 图片格式问题
            else if ((error + '').indexOf('加载图片文件失败') > -1) {
              that.$message.error('系统未能识别当前上传图片,请更换!');
            }
          }
          fileList.splice(fileList.indexOf(file), 1);
        })
        .always(function () {
          //不管成功或失败都会执行
          submit(reference, file);
        });
    }
  }
}
// 判断文件大小是否小于2M
function isLt2M(file) {
  if (file.raw.type === 'application/pdf') {
    return true;
  } else {
    return file.size / 1024 / 1024 < 2;
  }
}

function submit(reference, file) {
  let submitFlag = true;
  if (reference.multiple) {
    for (let item of reference.uploadFiles) {
      if (item.status != 'ready') {
        continue;
      }
      if (!isLt2M(item)) {
        submitFlag = false;
        break;
      } else {
        submitFlag = true;
      }
    }
  } else {
    if (!isLt2M(file)) {
      submitFlag = false;
    } else {
      submitFlag = true;
    }
  }
  if (submitFlag) {
    reference.submit();
    return;
  }
}

封装上传组件upload-image

<template>
  <div class="upload-component-container">
    <div class="upload-section">
      <!-- 上传主体 -->
      <el-row>
        <el-upload
          ref="imageUploadRef"
          :headers="token"
          :action="uploadUrl"
          :auto-upload="false"
          list-type="picture-card"
          :file-list="imageList"
          :on-change="resize"
          :on-remove="handleRemove"
          :on-preview="handlePreview"
          :on-success="handleSuccess"
          :on-error="handleError"
          :on-exceed="handleExceed"
          :on-progress="handleProgress"
          :class="imageList.length >= maxCount ? 'uploaded-none':''"
          :limit="maxCount"
        >
          <div class="icon-container" v-loading="loading">
            <i class="el-icon-plus upload-icon"></i>
          </div>
        </el-upload>
      </el-row>
      <!-- 上传描述 -->
      <el-row v-if="needDesc">
        <div class="upload-text-desc" :style="descStyle">{{uploadDesc}}</div>
      </el-row>
    </div>
    <!-- 🚀🚀🚀 查看图片 -->
    <el-dialog
      width="50%"
      :modal="modal"
      @close="imageVisible=false"
      :modal-append-to-body="false"
      :visible.sync="imageVisible"
    >
      <img width="100%" :src="dialogImageUrl" alt />
    </el-dialog>
  </div>
</template>
<script>
import { getBaseUrl, uuid as getUUId } from '@/utils/basic/' // 🚀 引入项目的api前缀
import { getToken } from '@/utils/browser' // 🚀 引入token
import { compress } from '@/utils/image/compress' // 🚀 引入上一步封装的压缩函数
import lodash from 'lodash'
export default {
  name: 'UploadImage',
  props: {
    modal: { type: Boolean, default: () => { false } },
    maxCount: { type: Number, required: true },
    uploadDesc: { type: String },
    initShowImages: { type: [Array, String], required: true },
    singleFile: { type: Boolean, default: false },
    needDesc: { type: Boolean, default: true },
    handleChange: { type: Function, required: true },
    descStyle: { type: Object, default: () => { null } }
  },
  data() {
    return {
      uploadUrl: getBaseUrl() + '/api/base/uploadImg',
      token: { Authorization: getToken(), 'X-Trace-ID': getUUId() },
      imageList: [],
      loading: false,
      imageVisible: false,
      dialogImageUrl: ''
    }
  },
  methods: {
    // 启用压缩
    resize(file, fileList) {
      compress(file, fileList, this, this.$refs.imageUploadRef)
    },
    // 上传成功
    handleSuccess(res, f, fList) {
      if (res.status === 1 && res.result.length > 0) {
        if (res.result[0].url) {
          this.imageList.push({
            url: res.result[0].url,
            // 兼容saas的初始 attachmentUrl 属性
            attachmentUrl: res.result[0].url // ❤❤❤
          })
        } else {
          this.imageList.push({
            url: fList[0].url,
            // 兼容saas的初始 attachmentUrl 属性
            attachmentUrl: fList[0].url // ❤❤❤
          })
        }
      }
      // 根据接收类型将结果发送到父组件
      if (this.singleFile == true) {
        this.handleChange(this.imageList[0].url)
      } else {
        this.handleChange(this.imageList)
      }
      this.loading = false
    },
    // 删除事件
    handleRemove(res) {
      this.imageList = lodash.filter(this.imageList, item => {
        if (res.response) {
          return item.url !== res.response.result[0].url
        } else {
          return item.url !== res.url
        }
      })
      // 根据接收类型将结果发送到父组件 => 单个文件
      if (this.singleFile == true) {
        this.handleChange('')
      } else {
        this.handleChange(this.imageList)
      }
      this.$forceUpdate()
    },

    // 最大数
    handleExceed() {
      this.$message({ type: 'warning', message: `最多上传${this.maxCount}张图片` })
    },
    // 上传错误
    handleError(err, file, fileList) {
      this.$message({ message: err.data.msg, type: 'error' })
    },
    // 查看图片
    handlePreview(file) {
      this.dialogImageUrl = file.url
      this.imageVisible = true
    },
    handleProgress() {
      this.loading = true
    }
  },
  mounted() {
    // case: string(logo)
    if (this.singleFile == true) {
      // 非空值
      if (this.initShowImages) {
        this.imageList.push({ url: this.initShowImages })
      } else {
        this.imageList = []
      }
    } else {
      // 列表文件
      this.imageList = this.initShowImages
    }
  },
  watch: {
    initShowImages(val) {
      // case: string(logo)
      if (this.singleFile == true) {
        // 非空值
        if (val) {
          this.imageList = [{ url: val }]
        } else {
          this.imageList = []
        }
      } else {
        // 列表文件
        this.imageList = val
      }
    }
  }
}
</script>
<style lang="scss">
.upload-component-container {
  .upload-section {
    background: #ffffff;
    border-radius: 4px;
    padding-top: 2px;
    .uploaded-none {
      .el-upload--picture-card {
        display: none;
      }
    }
    .el-upload-list--picture-card .el-upload-list__item {
      width: 60px;
      height: 60px;
    }
    .el-upload--picture-card {
      width: 60px;
      height: 60px;
      line-height: 125px;
      i {
        font-size: 20px !important;
      }
    }
    .icon-container {
      line-height: 2.5em;
      padding-top: 12px;
    }
    .el-icon-plus:before {
      // background: rgb(77, 227, 193);
      color: #000;
      border-radius: 12px;
    }
  }
  .upload-text-desc {
    font-size: 12px;
    color: #939393;
    margin-top: 4px;
    margin-bottom: 5px;
  }
}
</style>

在 vue 文件中使用

<template>
  <div class="contract-other-edit-container">
      <el-row>
        <el-col :span="12">
          <upload-image
            :modal="false"
            :maxCount="5"
            uploadDesc="格式要求:支持jpg/jpeg/bmp/gif/png格式图片,大小不超过20MB,多上传5张图片."
            :handleChange="handleUploadImage"
            :initShowImages="imageList"
          />
        </el-col>
      </el-row>
  </div>
</template>

<script>
import UploadImage from '@/components/element-ui/upload/image' // 组件的位置

export default {
  name: 'other-edit',
  components: { UploadImage },
  data() {
    return {
      imageList: []
    }
  },
  methods: {
    handleUploadImage(files) {
      this.imageList = files
    }
  }
}
</script>

posted @ 2020-07-23 10:49  荣光无限  阅读(1645)  评论(0编辑  收藏  举报