Vue 圖片壓縮并上傳至服務(wù)器功能
本文主要講解基于 Vue + Vant ,實(shí)現(xiàn)移動(dòng)端圖片選擇,并用 Canvas 壓縮圖片,最后上傳至服務(wù)器。還會(huì)封裝一個(gè)工具類,方便直接調(diào)用。
一、工具類封裝
廢話不多說先上代碼,封裝一個(gè) CompressImageUtils 工具類:
**
* 圖片壓縮工具類
* 最大高度和最大寬度都為 500,如果超出大小將等比例縮放。
*
* 注意可能出現(xiàn)壓縮后比原圖更大的情況,在調(diào)用的地方自己判斷大小并決定上傳壓縮前或壓縮后的圖到服務(wù)器。
*/
// 將base64轉(zhuǎn)換為blob
export function convertBase64UrlToBlob(urlData) {
let arr = urlData.split(',')
let mime = arr[0].match(/:(.*?);/)[1]
let bstr = atob(arr[1])
let n = bstr.length
let u8arr = new Uint8Array(n)
while (n--) {
u8arr[n] = bstr.charCodeAt(n)
}
return new Blob([u8arr], {type: mime})
}
// 壓縮圖片
export function compressImage(path) {
//最大高度
const maxHeight = 500;
//最大寬度
const maxWidth = 500;
return new Promise((resolve, reject) => {
let img = new Image();
img.src = path;
img.onload = function () {
const originHeight = img.height;
const originWidth = img.width;
let compressedWidth = img.height;
let compressedHeight = img.width;
if ((originWidth > maxWidth) && (originHeight > maxHeight)) {
// 更寬更高,
if ((originHeight / originWidth) > (maxHeight / maxWidth)) {
// 更加嚴(yán)重的高窄型,確定最大高,壓縮寬度
compressedHeight = maxHeight
compressedWidth = maxHeight * (originWidth / originHeight)
} else {
//更加嚴(yán)重的矮寬型, 確定最大寬,壓縮高度
compressedWidth = maxWidth
compressedHeight = maxWidth * (originHeight / originWidth)
}
} else if (originWidth > maxWidth && originHeight <= maxHeight) {
// 更寬,但比較矮,以maxWidth作為基準(zhǔn)
compressedWidth = maxWidth
compressedHeight = maxWidth * (originHeight / originWidth)
} else if (originWidth <= maxWidth && originHeight > maxHeight) {
// 比較窄,但很高,取maxHight為基準(zhǔn)
compressedHeight = maxHeight
compressedWidth = maxHeight * (originWidth / originHeight)
} else {
// 符合寬高限制,不做壓縮
}
// 生成canvas
let canvas = document.createElement('canvas');
let context = canvas.getContext('2d');
canvas.height = compressedHeight;
canvas.width = compressedWidth;
context.clearRect(0, 0, compressedWidth, compressedHeight);
context.drawImage(img, 0, 0, compressedWidth, compressedHeight);
let base64 = canvas.toDataURL('image/*', 0.8);
let blob = convertBase64UrlToBlob(base64);
// 回調(diào)函數(shù)返回blob的值。也可根據(jù)自己的需求返回base64的值
resolve(blob)
}
})
}
定義的最大寬度和最大高度均為 500,如果圖片的寬高至少有一個(gè)超出了 500,都會(huì)被 **等比例 **壓縮,不用擔(dān)心變形??梢愿鶕?jù)自己項(xiàng)目需要改變 maxWidth 和 maxHeight 。
這里直接把壓縮的最大高度和最大寬度寫死為 500 了,沒有在調(diào)用時(shí)傳。因?yàn)橐粋€(gè)項(xiàng)目壓縮的邏輯和大小一般都一致的,沒必要在每次調(diào)用的時(shí)候傳。當(dāng)然如果想寫的靈活一點(diǎn),可以在 compressImage 方法里再把 maxWidth 、 maxHeight 和壓縮質(zhì)量傳上。
compressImage 方法返回的是 blob 值,根據(jù)服務(wù)端接口需要可以改為返回 base64,只需將 resolve(blob) 改為 resolve(base64) 即可。
注意一點(diǎn),對(duì)于有些寬高沒到 500,且分辨率很小的圖片,壓縮之后可能比之前還大。猜測(cè)可能是 canvas 生成的圖片分辨率要比原來高一些,所以最終的圖片比壓縮前更大??梢栽谡{(diào)用的地方加個(gè)判斷,如果壓縮完的大小比原圖小,就上傳壓縮后的圖片;如果如果壓縮完的大小比原圖大,就上傳原圖。
二、如何使用
將 CompressImageUtils 引入到目標(biāo)文件,然后調(diào)用 compressImage 方法,即可在回調(diào)里獲得壓縮后的結(jié)果。注意 compressImage 方法返回的是 Promise。
省略其他無關(guān)代碼,只保留跟壓縮圖片和上傳相關(guān)的:
<template>
<div>
<van-uploader v-model="fileList" :after-read="afterRead" />
</div>
</template>
<script>
import {compressImage} from '../../utils/CompressImageUtils'
export default {
components: {},
methods: {
//讀取完圖片后
afterRead(file) {
console.log('afterRead------', file);
this._compressAndUploadFile(file);
},
//壓縮圖片上傳
_compressAndUploadFile(file) {
compressImage(file.content).then(result => {
console.log('壓縮后的結(jié)果', result); // result即為壓縮后的結(jié)果
console.log('壓縮前大小', file.file.size);
console.log('壓縮后大小', result.size);
if (result.size > file.file.size){
console.log('上傳原圖');
//壓縮后比原來更大,則將原圖上傳
this._uploadFile(file.file, file.file.name);
} else {
//壓縮后比原來小,上傳壓縮后的
console.log('上傳壓縮圖');
this._uploadFile(result, file.file.name)
}
})
},
//上傳圖片
_uploadFile(file, filename) {
let params = new FormData();
params.append("file", file, filename);
this.$api.uploadImage(params).then(res => {
console.log('uploadImage', res);
//上傳成功,寫自己的邏輯
}).catch(err => {
console.log('err', err);
});
},
}
}
</script>
在返回結(jié)果中加了層判斷,壓縮后比原來更大,則將原圖上傳;壓縮后比原來小,上傳壓縮后的。解決壓縮后比原圖更大的情況。
this.$api.uploadImage(params) 是調(diào)用封裝的 api 方法,如下:
//上傳圖片
uploadImage(params){
return axios.post(`${base}/api/v1/file`, params, {
headers: {'content-type': 'multipart/form-data'}
})
},
三、使用效果
先上傳一個(gè)非常大的,尺寸為 6016 × 4016,16.8M 的大圖,看輸出日志,壓縮后大小僅為 260k 左右。此時(shí)判斷壓縮后比壓縮前小,上傳壓縮圖到服務(wù)器。
再看個(gè)尺寸 300 × 300,12k 的小圖,壓縮前大小是 11252,壓縮后大小是 93656,大了很多。此時(shí)判斷壓縮后比壓縮前更大,上傳的是原圖。
總結(jié):這個(gè)工具類對(duì)大圖的壓縮效果很明顯,不管多大的圖,壓縮之后基本不會(huì)超過 300k。但對(duì)某些小圖可能出現(xiàn)壓縮完反而更大的情況。在調(diào)用的地方加層壓縮后和壓縮前大小的比較判斷,會(huì)完美解決這個(gè)問題。
當(dāng)然也可以在工具類內(nèi)部判斷,但個(gè)人覺得跟業(yè)務(wù)邏輯相關(guān)的代碼還是不要放在公用的工具類比較好。
總結(jié)
以上所述是小編給大家介紹的Vue 圖片壓縮并上傳至服務(wù)器功能,希望對(duì)大家有所幫助,如果大家有任何疑問請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!
如果你覺得本文對(duì)你有幫助,歡迎轉(zhuǎn)載,煩請(qǐng)注明出處,謝謝!
相關(guān)文章
vue單應(yīng)用在ios系統(tǒng)中實(shí)現(xiàn)微信分享功能操作
這篇文章主要介紹了vue單應(yīng)用在ios系統(tǒng)中實(shí)現(xiàn)微信分享功能操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-09-09
vue前端img訪問鑒權(quán)后端進(jìn)行攔截的代碼示例
路由攔截是一種在用戶訪問特定頁面之前對(duì)其進(jìn)行攔截和處理的機(jī)制,下面這篇文章主要給大家介紹了關(guān)于vue前端img訪問鑒權(quán)后端進(jìn)行攔截的相關(guān)資料,需要的朋友可以參考下2024-03-03
vue?router如何實(shí)現(xiàn)tab切換
這篇文章主要介紹了vue?router如何實(shí)現(xiàn)tab切換,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-04-04
vue實(shí)現(xiàn)拖動(dòng)調(diào)整左右兩側(cè)容器大小
這篇文章主要為大家詳細(xì)介紹了vue實(shí)現(xiàn)拖動(dòng)調(diào)整左右兩側(cè)容器大小,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03
vue-calendar-component 封裝多日期選擇組件的實(shí)例代碼
這篇文章主要介紹了vue-calendar-component 封裝多日期選擇組件,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-12-12

