uniapp小程序圖片前端壓縮上傳


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)
				})
			})
		})
	}
}

如果看了覺得有幫助的,我是@上進的鵬多多,歡迎 點贊 關注 評論;END


PS:在本頁按F12,在console中輸入document.querySelectorAll('.diggit')[0].click(),有驚喜哦


面向百度編程

公眾號

weixinQRcode.png

往期文章

個人主頁


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM