【uniapp】uniapp 使用uView框架 upload組件壓縮圖片

来源:https://www.cnblogs.com/mengyilingjian/archive/2022/08/18/16599139.html
-Advertisement-
Play Games

tips:如果本文對你有用,請愛心點個贊,提高排名,讓這篇文章幫助更多的人。謝謝大家!比心❤~ 如果解決不了,可以在文末加我微信,進群交流。 技術選型 開發框架: uniapp 主題UI框架: uView 背景 uView框架upload文件上傳組件中沒有h5端控制壓縮的參數,超出文件大小也沒有響應 ...


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】,進群一起技術討論。添加時請備註來意,謝謝!

如果本文對你有幫助,請【關註】【打賞】【分享】
有問題請添加個人微信:【mengyilingjian】,添加時請備註來意,謝謝!
添加好友打賞碼
本文歡迎各位轉載,但是轉載文章之後必須在文章頁面中給出作者和原文出處鏈接。
★★★★★★★★★★來都來了,點個贊再走唄★★★★★★★★★★
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 自6月底開源以來,許多熱心的社區用戶都對StoneDB進行了編譯和測試,也有一些用戶詢問StoneDB是否會支持Windows。雖然適配Windows版本的StoneDB尚未進入研發計劃,但實際上我們也可以通過強大的docker在windows上體驗StoneDB的性能。本文就從一個初學者角度,帶大 ...
  • 用戶在App里搜索某個地點時,並不滿足單一的地點信息,希望得到更多可以幫助其做決策的深度信息。例如有打車出行需求的用戶,在打車App里搜索地點時可以顯示周邊的地點,精確到某個路口,讓用戶可以自由選擇合適的上下車點。銀行金融App類可以讓用戶在搜索時顯示附近線下網點和營業時間、電話以及周邊道路信息等。 ...
  • 3 數據類型 3.1 簡介 JavaScript中的每個值都是屬於一種特定的數據類型。JavaScript中一共有以下幾種數據類型,詳細如下所示: 原始類型:Undefined、Null、Boolean、Number、String 和Symbol 對象:Object 通常將數值、字元串和布爾值三種類 ...
  • 前言 本文主要是對Promise本身的用法做一個全面解析而非它的原理實現,如果你對Promise的用法還不是很熟悉或者想加深你對Promise的理解,我相信這篇文章一定會幫到你。 首先讓我們先瞭解一下JavaScript為什麼會引入Promise 回調地獄 讓我們先看這樣一段代碼,JQuery中aj ...
  • 本文是深入淺出 ahooks 源碼系列文章的第八篇,該系列已整理成文檔-地址。覺得還不錯,給個 star 支持一下哈,Thanks。 本篇文章算是該系列的一個彩蛋篇,記錄一下第一次給開源項目提 PR 的過程(之前好像也有過,不過那個非常小的一個改動),希望能夠幫助更多的人參與到開源項目中來。 起因 ...
  • 防抖 概述:在規定時間內只執行一次(執行最後一次) 舉個例子:電梯關門案例 a 進入電梯 等待5s後 就可以上升了 在a等待了4s中後 b過來 那麼之前的等待就結束了 開始新的等待 在b等待了3s後 c過來 那麼之前的等待也結束了 開始新的等待 .... 直到最後一次等待結束 電梯就上升 (實際電梯 ...
  • day1 javascript三種引入方式 三種輸出方式 變數 數據類型 查看數據類型 判斷是否為數字 javascript三種引入方式 行內式 <a href="javascript:alert('hello word')">噠噠噠</a> <div onclick="alert('你好')">我 ...
  • 前端使用 vite 構建,vite 利用了瀏覽器原生的 module 載入,速度極快。創建一個 node 伺服器,使用 koa 框架。簡簡單單,一個全新的全棧項目就搭起來啦。 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...