• antdv的Upload组件实现前端压缩图片并自定义上传功能


    Ant Design of Vue的Upload组件有几个重要的api属性:

    beforeUpload: 上传文件之前的钩子函数,支持返回一个Promise对象。

    customRequest: 覆盖组件默认的上传行为,实现自定义的上传请求。

    功能实现原理

    在上传图片前获取该图片的文件流(beforeUpload中获取),对这个文件流进行压缩操作,再将压缩后的文件流传过去(resolve(newFile)),最后进行自定义的上传请求(customRequest中实现)。

    图片预览方式

    前端本地图片的预览则可以选择blob或者base64的方式,本文推荐使用blob方式来预览图片。

    部分代码

    html

    <template>
      <div>
        <a-spin :spinning="isShowSpinning">
          <img
            v-if="imageUrl"
            :src="imageUrl"
            style=" 200px; height: 200px; margin-right: 10px;"
          />
          <a-upload
            accept="image/*"
            :beforeUpload="beforeImageUpload"
            :customRequest="customImageRequest"
          >
            <a-button type="primary">
              <a-icon type="upload" />上传
            </a-button>
          </a-upload>
        </a-spin>
      </div>
    </template>
    

    api

    import request from '@/utils/request'
    
    const api = {
        uplodBackName: '/biz/uplodBackName'
    }
    
    export function getUplodBackName (parameter) {
      return request({
        url: api.uplodBackName,
        method: 'post',
        // 传输文件流需要单独设置请求头
        headers: {
          'Content-Type': 'multipart/form-data'
        },
        data: parameter
      })
    }
    

    js

    <script>
    import { getUplodBackName } from '@/api/biz/manage'
    
    export default {
      components: {},
      data () {
        return {
          imageUrl: '',
          isShowSpinning: false
        }
      },
      methods: {
        // 上传图片前的钩子函数
        beforeImageUpload (file, fileList) {
          return new Promise(async (resolve, reject) => {
            if (!file.type.includes('image')) {
              this.$message.warning('请上传图片')
              reject(new Error('请上传图片'))
              return
            }
            this.isShowSpinning = true
            const newFile = await this.compressImg(file)
            resolve(newFile)
          })
        },
        // 自定义的上传请求
        customImageRequest (info) {
          const { file } = info
          // blob方式预览图片
          this.imageUrl = window.URL.createObjectURL(file)
          // 组装数据
          const formData = new FormData()
          formData.append('files', file)
          // 发送请求
          getUplodBackName(formData).then(res => {
            this.$message.success('上传成功')
          }).catch(() => {
            this.$message.warning('上传失败')
          }).finally(() => {
            this.isShowSpinning = false
          })
        },
        // base64转码(压缩完成后的图片为base64编码,这个方法可以将base64编码转回file文件)
        dataURLtoFile (dataurl, filename) {
          var arr = dataurl.split(',')
          var mime = arr[0].match(/:(.*?);/)[1]
          var bstr = atob(arr[1])
          var n = bstr.length
          var u8arr = new Uint8Array(n)
          while (n--) {
            u8arr[n] = bstr.charCodeAt(n)
          }
          return new File([u8arr], filename, { type: mime })
        },
        // 图片压缩函数
        compressImg (file) {
          const that = this
          var files
          var fileSize = parseFloat(parseInt(file['size']) / 1024 / 1024).toFixed(2)
          var read = new FileReader()
          read.readAsDataURL(file)
          return new Promise(function (resolve, reject) {
            read.onload = function (e) {
              var img = new Image()
              img.src = e.target.result
              img.onload = function () {
                // 默认按比例压缩
                var w = this.width
                var h = this.height
                // 生成canvas
                var canvas = document.createElement('canvas')
                var ctx = canvas.getContext('2d')
                var base64
                // 创建属性节点
                canvas.setAttribute('width', w)
                canvas.setAttribute('height', h)
                ctx.drawImage(this, 0, 0, w, h)
                if (fileSize < 1) {
                  // 如果图片小于一兆 那么压缩0.5
                  base64 = canvas.toDataURL(file['type'], 0.5)
                } else if (fileSize > 1 && fileSize < 2) {
                  // 如果图片大于1M并且小于2M 那么压缩0.5
                  base64 = canvas.toDataURL(file['type'], 0.5)
                } else {
                  // 如果图片超过2m 那么压缩0.2
                  base64 = canvas.toDataURL(file['type'], 0.2)
                }
                // 回调函数返回file的值(将base64编码转成file)
                files = that.dataURLtoFile(base64, file.name) // 如果后台接收类型为base64的话这一步可以省略
                resolve(files)
              }
            }
          })
        }
      }
    }
    </script>
    

    效果预览

    压缩效果

    根据实测,5MB的图片可以压缩到200KB,画质上,肉眼观察基本不变。

    如有错误,请多指教,谢谢!

  • 相关阅读:
    GFS读后笔记
    BigTable读后笔记
    恢复系统基础理论
    事务基础理论
    ARIES算法简介
    怎么快速构建自己的C/C++程序?——有关编译、静态链接和SCons
    lua学习笔记
    运行时动态伪造vsprintf的va_list
    11月30日站立会议
    11月29号站立会议
  • 原文地址:https://www.cnblogs.com/ykCoder/p/14156450.html
Copyright © 2020-2023  润新知