uniapp压缩图片的api,uni.compressimage在h5环境暂不支持,详见官网-平台差异说明
所以我们在这件事情上,需要超越uniapp官方。诶 听起来还不错
代码里面有一些vk.的操作,这是个2022年出来的云开发框架,vk的特点是让写JS的前端三天内变成全栈。有兴趣可以戳链接了解,vk的作者还坑过我一次害我22点饿着肚子在加班。vk框架秒变全栈
Q:为什么压缩(that.compressImage)和上传(that.uploadImg)都用到Promise.all()?
因为我们是支持批量上传,当选择10张图片时,我们没有理由压缩完一张再压缩下一张,JS默认是单线程执行代码。所以我们需要优化,面试时聊得最多的优化。
uploadFile() {
let type = that.queryForm1.formData.type;
let fileType;
let extension = [];
if (type === "image") {
extension = ["png", "jpg", "jpeg", "gif", "bmp", "svg"];
fileType = "image";
} else if (type === "video") {
extension = ["avi", "mp3", "mp4", "3gp", "mov", "rmvb", "rm", "flv", "mkv"];
fileType = "video";
} else if (type === "other") {
extension = ["txt", "pdf", "xls", "xlsx", "ppt", "pptx", "doc", "docx", "rar", "zip"];
}
const tasksUload = [];
const tasksCompress = [];
uni.chooseFile({
extension,
success: res => {
vk.showLoading("上传中...");
const {
tempFilePaths,
tempFiles
} = res
tempFiles.forEach((file, index) => {
console.log(`图片大小:${file.size}====图片名称:${file.name}====类型${file.type}`)
const filePath = tempFilePaths[index]
// 图片大于1MB进行压缩
if (fileType == 'image' && file.size / 1024 > 1025) {
tasksCompress.push(that.compressImage(file))
} else {
tasksUload.push(that.uploadImg(file, fileType))
}
})
if (tasksCompress.length > 0) {
Promise.all(tasksCompress).then(files => {
// 压缩完毕,拿到压缩后的图片文件数组files
files.forEach(file => tasksUload.push(that.uploadImg(file, fileType)))
uploadFu()
})
} else {
uploadFu()
}
}
});
function uploadFu() {
Promise.all(tasksUload)
.then(res1 => {
vk.hideLoading();
that.getList();// 自己的查询接口
})
.catch(err => {
vk.hideLoading();
console.error(err);
});
}
},
以下是传统前端压缩思路(应该还有更高级的,可我不会,希望有大佬来评论区分享下)
uni.getImageInfo得到图片的信息
把图片画到cavans上,这一步图片已经被压缩
使用cavans的toDataURL方法得到base64文件流的格式
因为后端懒得处理base64二进制,所以我们前端要把base64二进制再转成File文件格式
Q:什么是base64二进制?
它是以data:image/png;base64开头的格式,png也可能是jpg、svg等图片类型。
它是包括小写字母a-z、大写字母A-Z、数字0-9、符号"+"、"/"一共64个字符的字符集。
更详细讲解
Q:为什么png图片格式不能压缩,需要转成jpge?
因为 canvas 是不支持无损的 png 压缩的。如果我们要进行压缩,那就需要转为 jpeg ,同时 png 的透明效果将会消失。
// 压缩图片
compressImage(urlData) {
vk.showLoading("压缩中...");
const asyncFunc = new Promise(resolve => {
uni.getImageInfo({
src: urlData.path,
success(res) {
let originWidth = res.width; //图片原始宽
let originHeight = res.height; //图片原始高
let img = new Image()
img.src = res.path
let canvas = document.createElement('canvas');
let ctx = canvas.getContext('2d')
// 目标尺寸
let targetWidth = originWidth;
let targetHeight = originHeight;
canvas.width = targetWidth
canvas.height = targetHeight
// 图片压缩
ctx.drawImage(img, 0, 0, targetWidth, targetHeight)
// 将png格式文件转为jepg输出,因为png图片不能用这种方式进行压缩
let filetype = urlData.type === 'image/png' ? 'image/jpeg' : urlData.type
// canvas对图片进行缩放 0.5是我定义的图片质量
let base64 = canvas.toDataURL(filetype, 0.5);
// 将base64转换为filel流
let flie = that.convertBase64UrlToFile({
dataURL: base64,
type: urlData.type,
contentName: urlData.name
})
console.log('压缩后', flie)
resolve(flie)
},
fail() {
uni.showModal({
title: '提示',
content: '图片压缩失败',
showCancel: false
});
}
})
})
return asyncFunc
},
说实话这段代码比较底层,我是看不太懂的,可如果我们看懂了,面试时我们便是见多识广,游刃有余,天下无敌
Q:window.atob()是什么?
btoa():从二进制数据“字符串”创建一个 Base-64 编码的 ASCII 字符串(“btoa”应读作“binary to ASCII”)
atob():解码通过 Base-64 编码的字符串数据(“atob”应读作“ASCII to binary”)
// base64转成File文件格式
convertBase64UrlToFile(base64) {
let urlData = base64.dataURL
let type = base64.type
let contentName = base64.contentName
let bytes = null
if (urlData.split(',').length > 1) { //是否带前缀
bytes = window.atob(urlData.split(',')[1]) // 去掉url的头,并转换为byte
} else {
bytes = window.atob(urlData)
}
// 处理异常,将ascii码小于0的转换为大于0
let ab = new ArrayBuffer(bytes.length)
let ia = new Uint8Array(ab)
for (let i = 0; i < bytes.length; i++) {
ia[i] = bytes.charCodeAt(i)
}
let result = new Blob([ab], {
type: type,
})
let result1 = new File([result], contentName, {
type: type
})
result1.path = window.URL.createObjectURL(result)
return result1
},
我这里是vk的api方法,大家换成自己的axios请求就好
// 上传图片到云存储
uploadImg(file, fileType) {
const asyncUload = new Promise(function(resolve, reject) {
vk.callFunctionUtil.uploadFile({
filePath: file.path,
file: file,
needSave: true,
fileType,
category_id: that.queryForm1.formData.category_id,
addSuccess: function(res) {
// 等保存到数据库后才执行resolve
resolve(res);
}
});
})
return asyncUload
},