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

2 篇文章 0 订阅

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

技术选型
背景

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】,进群一起技术讨论。添加时请备注来意,谢谢!

  • 4
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值