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>