1,前言

这次项目中做了一个图片上传,要求是大于2MB的就压缩成2MB一下的再上传,我这边利用了uniapp的文件接口,使用canvas做了一个压缩上传的功能,目前已上线,使用无问题。

2,实现代码


定义canvas

<canvas canvas-id="imgCanvas" class="imgCanvas" />

canvas样式

.imgCanvas{
	position: absolute;
	top: -100%;
	width: 100%;
	height: 100%;
}

定义数据

// 引入图片压缩的方法
import { imgCompress } from '../../utils/index.js'
// 定义2MB
const Limit = 1024 * 1024 * 2
// 页面数据
data() {
	return {
		imgsPath: [], // 图片路径ID
		imgsUrl: [] // 查看大图
	}
}

打开相册

// 打开相册
handleOpenPhoto() {
	const _this = this
	uni.chooseImage({
		success: (chooseImageRes) => {
			const imgPaths = chooseImageRes.tempFiles
			const successUp = 0 // 成功计数
			const failUp = 0 // 失败计数
			const count = 0 // 第几张
			const total = imgPaths.length // 当前已上传个数
			// 调用上传方法
			_this.recursionUploading(imgPaths, successUp, failUp, count, total)
		},
		fail: (error) => {
			console.warn(error)
		}
	})
}

递归上传

/**
 * 递归上传
 * @param {String} imgPaths 上传的图片地址
 * @param {String} successUp 成功个数
 * @param {String} failUp 失败个数
 * @param {String} count 当前第几张
 * @param {String} total 总数
 */
async recursionUploading(imgPaths, successUp, failUp, count, total) {
	const _this = this
	Loading.hide()
	Loading.show(`上传第${count + 1}张...`)
	let initPath = imgPaths[count].path
	// 如果超过2MB就压缩
	if (imgPaths[count].size > Limit) {
		Loading.hide()
		Loading.show(`${count + 1}张压缩中...`)
		initPath = await imgCompress.getCompressImage(imgPaths[count], 2)
	}
	uni.uploadFile({
		header: {
			'content-type': 'multipart/form-data',
			'channel': '3',
			'token': app.globalData.user.userToken
		},
		url: `${app.globalData.baseURL}/oss/uploadFile`,
		filePath: initPath,
		name: 'file',
		formData: {
			segmentId: 'WKDPE'
		},
		success: (uploadFileRes) => {
			const res = JSON.parse(uploadFileRes.data)
			if (res.code === '00000') {
				_this.imgsPath.push({
					path: imgPaths[count].path,
					fileId: res.data.fileId
				})
				_this.imgsUrl.push(imgPaths[count].path)
				successUp++ // 成功+1
			} else {
				failUp++
			}
		},
		fail(e) {
			failUp++ // 失败+1
		},
		complete(res) {
			const data = JSON.parse(res.data)
			if (data.code === '99990') {
				uni.removeStorageSync('userInfo')
				uni.removeStorageSync('user')
				app.globalData.user = {}
				app.globalData.userInfo = {}
				Toast(data.message)
				setTimeout(() => {
					uni.reLaunch({
						url: '../login/index'
					})
				}, 1000)
				return
			}
			count++ // 下一张
			if (count == total) {
				Toast(`上传结束,总共${count}张,失败${failUp}张 !`)
			} else {
				// 递归调用,上传下一张
				_this.recursionUploading(imgPaths, successUp, failUp, count, total);
			}
		}
	})
}

删除照片

/**
 * 删除照片
 * @param {String} id 图片id
 */
deleteImg(id) {
	const index = this.imgsPath.findIndex(item => {
		return item.fileId === id
	})
	this.imgsPath.splice(index, 1)
}

预览大图

/**
 * 预览大图
 * @param {String} url 图片地址
 * @param {String} index 当前图片下标
 */
handlePreviewImage(url, index) {
	const _this = this
	uni.previewImage({
		urls: _this.imgsUrl,
		current: index,
		longPressActions: {
			itemList: ['发送给朋友', '保存图片'],
			success: function(data) {
				console.log('选中了第' + (data.tapIndex + 1) + '个按钮,第' + (data.index + 1) + '张图片')
			},
			fail: function(err) {
				console.log(err.errMsg)
			}
		}
	})
}

压缩图片

/**
 * 压缩图片
 * @param {Object} file { path: '', size: '' }
 * @param {Number} limitSize 压缩目标 MB
 */
export const imgCompress = {
	MB: 1024 * 1024,
	canvasId: 'imgCanvas',
	ctx: uni.createCanvasContext('imgCanvas'),
	// 获取可使用窗口宽度(提前使用uni.getSystemInfo获取windowWidth存在globalData)
	rpxToPx(number) {
		return number / 750 * getApp().globalData.systemInfo.windowWidth
	},
	// 获取文件信息
	getFileInfo(path) {
		return new Promise((resolve, reject) => {
			uni.getFileInfo({
				filePath: path,
				success: (res) => {
					console.log('File Size =>', `${res.size / this.MB}MB`)
					resolve(res.size)
				},
				fail: () => reject(null)
			})
		})
	},
	// 获取图片信息
	getImageInfo(path) {
		return new Promise((resolve, reject) => {
			uni.getImageInfo({
				src: path,
				success: (res) => resolve(res),
				fail: () => reject(null)
			})
		})
	},
	// 判断是否达到压缩目标
	getCompressImage(file, limitSize) {
		if (file.size > this.MB * limitSize) {
			return this.calcImaeg(file.path, limitSize);
		} else {
			return file.url
		}
	},
	// 递归
	async calcImaeg(url, limitSize) {
		const size = await this.getFileInfo(url)
		if (size > this.MB * limitSize) {
			const imageInfo = await this.getImageInfo(url)
			var maxSide = Math.max(imageInfo.width, imageInfo.height);
			var windowW = this.rpxToPx(750)
			var scale = 1
			if (maxSide > windowW) {
				scale = windowW / maxSide;
			}
			var imageW = Math.floor(imageInfo.width * scale)
			var imageH = Math.floor(imageInfo.height * scale)
			const newPath = await this.getCanvasImage(url, imageW, imageH)
			return this.calcImaeg(newPath, limitSize)
		} else {
			return url
		}
	},
	// 绘画
	getCanvasImage(imagePath, imageW, imageH) {
		return new Promise((resolve, reject) => {
			this.ctx.drawImage(imagePath, 0, 0, imageW, imageH)
			this.ctx.draw(false, () => {
				uni.canvasToTempFilePath({
					canvasId: this.canvasId,
					x: 0,
					y: 0,
					width: imageW,
					height: imageH,
					quality: 1,
					success: (res) => resolve(res.tempFilePath),
					fail: () => reject(imagePath)
				})
			})
		})
	}
}

本次分享就到这儿啦,我是鹏多多,如果您看了觉得有帮助,欢迎评论,关注,点赞,转发,我们下次见~

往期文章

个人主页

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐