【uniapp】uniapp 使用uView框架 upload组件压缩图片

tips:如果本文对你有用,请爱心点个赞,提高排名,让这篇文章帮助更多的人。谢谢大家!比心❤~
如果解决不了,可以在文末加我微信,进群交流。

技术选型

  • 开发框架: uniapp
  • 主题UI框架: uView

背景

uView框架upload文件上传组件中没有h5端控制压缩的参数,超出文件大小也没有响应的提示,但是一般的上传文件场景,是需要控制文件大小的。

在这里插入图片描述


效果图

原图是4.8M,长宽为:3024*4032
原图
质量宽高同比例压缩
压缩质量,不调整宽高


封装图片压缩工具方法

  • 封装util.js
 // 图片压缩
/**
* imgSrc 地址
* scale 压缩质量 0-1
* type 文件类型
*/
export function compressImg(imgSrc, scale, type, callback) {
// uni.$u.toast('压缩中')
var img = new Image();
img.src = imgSrc;
img.onload = function() {
var that = this;
var h = (img.height * scale).toFixed(0); // 默认按质量比例压缩
var w = (img.width * scale).toFixed(0);
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
var width = document.createAttribute("width");
width.nodeValue = w;
var height = document.createAttribute("height");
height.nodeValue = h;
canvas.setAttributeNode(width);
canvas.setAttributeNode(height);
ctx.drawImage(that, 0, 0, w, h);
var base64 = canvas.toDataURL('image/jpeg', scale); //压缩比例
canvas = null;
if (type == 'base64') {
let data = {
size: getBase64Size(base64),
type: type,
source: base64
}
callback(base64);
} else {
let blob = base64ToBlob(base64);
// console.log('压缩后的大小', blob, blob.size, blob.type)
const blobUrl = window.URL.createObjectURL(blob); //blob地址
blob.source = blobUrl
callback(blob);
}
}
}

// base转Blob
export function base64ToBlob(base64) {
var arr = base64.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 Blob([u8arr], {
type: mime
});
}

// 获取base64的文件大小
export function getBase64Size(base64Str) {
let size = 0;
if (base64Str) { // 获取base64图片byte大小
const equalIndex = base64Str.indexOf('='); // 获取=号下标
if (equalIndex > 0) {
const str = base64Str.substring(0, equalIndex); // 去除=号
const strLength = str.length;
const fileLength = strLength - (strLength / 8) * 2; // 真实的图片byte大小
size = Math.floor(fileLength); // 向下取整
} else {
const strLength = base64Str.length;
const fileLength = strLength - (strLength / 8) * 2;
size = Math.floor(fileLength); // 向下取整
}
} else {
size = null;
}
return size
}
index.vue中引入util.js,并在上传时使用
 <template>
<view class="components-wrap">
<u-form-item class='form-item-box' labelWidth='auto' :prop="column.name" borderBottom :ref="column.name">
<u-upload class="upload-wrap" width="102" :fileList="fileList" @afterRead="afterRead" @delete="deletePic"
:sizeType="sizeType" @clickPreview="clickPreview" :name="column.name" multiple :disabled="disabled"
:formkey="formkey">
<view class="material-add">
<u-button class='upload-btn' :disabled="disabled" text="上传图片"></u-button>
</view>
</u-upload>
</u-form-item>
</view>
</template>
<script>
import {
compressImg
} from '@/utils/util.js'
export default {
data() {
return {
currentValue: false,
fileList: [],
sizeType: ['compressed'],
fileMaxSize: 2 * 1024 * 1024, // 默认最大为2M
fileMinSize: 50 * 1024 // 最小为50KB
}
},
methods: {
clickPreview(url, lists, name) {
console.log('预览图片', url, lists, name)
},
getCompressionRatio(fileSize) {
const multiple = (fileSize / this.fileMaxSize).toFixed(2) // 获取文件大小倍数,生成质量比
let compressionRatio = 1
if(multiple > 5) {
compressionRatio = 0.5
} else if (multiple > 4) {
compressionRatio = 0.6
} else if (multiple > 3) {
compressionRatio = 0.7
}else if (multiple > 2) {
compressionRatio = 0.8
} else if (multiple > 1) {
compressionRatio = 0.9
} else {
compressionRatio = 2
}
return compressionRatio;
},
// 新增图片
async afterRead(event) {
// 当设置 mutiple 为 true 时, file 为数组格式,否则为对象格式
let lists = [].concat(event.file)
let fileListLen = this[`fileList`].length

for (let index in lists) {
const item = lists[index]
const fileSize = item.size
const fileName = item.name ?? ''
if (fileSize > this.fileMaxSize) {
const compressionRatio = this.getCompressionRatio(fileSize)
if (compressionRatio > 1) {
uni.$u.toast('文件' + fileName + '大于10M')
return false
}
// 自动压缩图片'
await this.compressImg(item, compressionRatio)
if (item.size > this.fileMaxSize) {
uni.$u.toast('文件' + fileName + '压缩后超出2M')
return false
}
}

if (item.size < this.fileMinSize) {
uni.$u.toast('文件' + fileName + '不能小于50KB')
return false
}

this[`fileList`].push({
...item,
status: 'uploading',
message: '上传中'
})
}
for (let i = 0; i < lists.length; i++) {

const result = await this.uploadFilePromise(lists[i].url)
// 垃圾回收
window.URL.revokeObjectURL(lists[i].url)
console.log('上传结果', result)
let item = this[`fileList`][fileListLen]
this[`fileList`].splice(fileListLen, 1, Object.assign(item, {
status: 'success',
message: '上传成功',
url: result
}))
fileListLen++
}
},
compressImg(source, compressionRatio) {
return new Promise((resolve, reject) => {
compressImg(source.url, compressionRatio, source.type, compressRes => {
resolve(compressRes);
})
}).then((res) => {
source.size = res.size
// window.URL.revokeObjectURL(source.url) // 删除被压缩的缓存文件,这里注意,如果是相册选择上传,可能会删除相册的图片
source.url = res.source
source.thumb = res.source
return source
}).catch(err => {
console.log('图片压缩失败', err)
})
},
uploadFilePromise(url) {
let that = this
return new Promise((resolve, reject) => {
const uploadTask = uni.uploadFile({
url: uploadUrl,
filePath: url,
name: 'file',
header: {
"blade-auth": "Bearer xxxxxxxxxxxxx",
"tenantCode": tenantCode
},
success: (uploadFileRes) => {
if (uploadFileRes.statusCode === that.Response.OK) {
const data = JSON.parse(uploadFileRes.data)
if (data.code === that.Response.OK) {
console.log('form components upload uploadFilePromise onchange',
uploadFileRes)
let fileId = data.data[0].id;
const sourceUrl = 'https://xxxxxxx/download-document/id/' + fileId;
that.data.value.push({
id: fileId,
name: data.data[0].name,
source: sourceUrl
});
// 添加图片数量
that.data.count = that.fileList.length
that.$emit('change', that.data, that.formkey)
setTimeout(() => {
resolve(sourceUrl)
}, 500)
} else {
uni.showToast({
title: data.msg,
icon: 'none',
duration: that.ShowToast.DURATION
});
}
} else {
console.log(uploadFileRes)
uni.showToast({
title: '上传失败',
icon: 'none',
duration: that.ShowToast.DURATION
});
}
},
fail(error) {
// reject(false)
uni.$u.toast(error.errMsg)
console.log('图片上传失败', error)
}
});

// uploadTask.onProgressUpdate((res) => {
// console.log('上传进度' + res.progress);
// console.log('已经上传的数据长度' + res.totalBytesSent);
// console.log('预期需要上传的数据总长度' + res.totalBytesExpectedToSend);

// // 测试条件,取消上传任务。
// if (res.progress > 50) {
// uploadTask.abort();
// }
// });
})
},
}
}
<script/>

有问题请添加个人微信:【mengyilingjian】,进群一起技术讨论。添加时请备注来意,谢谢!

标签: Javascript

添加新评论