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="width: 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,畫質上,肉眼觀察基本不變。

如有錯誤,請多指教,謝謝!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM