element前端實現(xiàn)壓縮圖片的功能
前言
隨著現(xiàn)在手機像素,拍照功能越來越好,隨之而來的是本地圖片越來越大,那么如何更好的將本地圖片上傳到后端接口呢?這是后臺管理系統(tǒng)常見的場景和頭疼的問題,這里分享下個人的方法。
實現(xiàn)效果
如下圖所示,從 580kb -> 壓縮后 150kb


實現(xiàn)步驟
1、父級引入封裝文件
//頁面上
<el-dialog
title="壓縮圖片"
:visible.sync="compressImgVisible"
width="700"
foot-hide
>
<uploadImg
/>
</el-dialog>
//js中
data() {
return {
compressImgVisible: false,
}2、首先實現(xiàn)上傳功能,使用el-upload,
封裝uploadImg.vue
<template>
<div class="uploadImgBody">
<!--上傳圖片部分-->
<el-upload
class="upload-image"
ref="upload"
:action="action"
:headers="headers"
:multiple="multiple"
:data="data"
:name="name"
:show-file-list="showFileList"
:drag="drag"
:accept="accept"
:list-type="listType"
:auto-upload="autoUpload"
:disabled="is_disabled"
:before-upload="beforeUpload"
>
<!--彈框展示上傳以后的圖片-->
<img
class="fileImg"
v-if="mrImgUrl"
:src="mrImgUrl"
>
<div v-else>
<i class="el-icon-plus"></i>
</div>
</el-upload>
</div>
</template>
<script>
//element的上傳圖片,壓縮圖片組件
export default {
props:{
/**
* 自動上傳參數(shù)
* */
autoUpload:{ // 是否需要選取完自動上傳功能
type: Boolean,
default: true
},
// 默認圖片,父級傳過來 http開頭的文件
mrImgUrl:{
type: String,
default: ''
},
action:{//上傳的地址
type: String,
default: ''
},
headers: {//設(shè)置上傳的請求頭部
type:Object,
default: () => {
return {}
}
},
data: {//上傳時額外帶的參數(shù)
type:Object,
default: () => {
return {}
}
},
name:{//上傳的文件字段名
type: String,
default: 'file'
},
cookieOK:{//支持發(fā)送 cookie 憑證信息
type: Boolean,
default: true
},
/**
* 公共參數(shù)
* */
showFileList:{//是否顯示已上傳文件列表
type: Boolean,
default: false
},
drag:{//是否啟用拖拽上傳
type: Boolean,
default: false
},
accept:{//接受文件類型-圖片上傳類型-不同的格式之間以逗號隔開
type: String,
default: '.jpg,.jpeg,.png'
},
listType:{ // 文件列表的類型 - text/picture/picture-card
type: String,
default: 'picture-card'
},
fileList:{//已上傳的文件列表,
type:Array,
default: () => {
return [
{
name: 'food.jpeg',
url: 'https://fuss10.elemecdn.com/3/63/4e7f3a15429bfda99bce42a18cdd1jpeg.jpeg?imageMogr2/thumbnail/360x360/format/webp/quality/100'
}
]
}
},
is_disabled:{//是否禁止,true是禁止,false不禁止
type: Boolean,
default: false
},
multiple:{//是否可以多選
type: Boolean,
default: true
},
},
watch: {},
data() {
return {
}
},
methods: {
/**
* @上傳文件之前的鉤子
* @params file 圖片的file文件
* @return uploadFile 把文件發(fā)送給父級
* @tip 多選會調(diào)用多次該方法
*/
beforeUpload(file) {
this.$emit('uploadFile',file);
return
}
},
}
</script>
<style lang='scss' scoped>
.uploadImgBody{
height: auto;
.upload-image{
width:200px;
height: 200px;
.fileImg{
width:100%;
height: 100%;
}
}
.showImg{
width:100px;
height: 100px;
}
}
</style>3、加入壓縮功能
邏輯:
首先,把file文件轉(zhuǎn)成 canvas圖片,然后canvas壓縮圖片利用canvas.toDataURL()將canvas繪制的圖像轉(zhuǎn)成圖片從而達到壓縮圖片尺寸的效果

具體方法:其中 dataUrl 就是拿到的canvas圖片的base64地址
/**
* @壓縮公共方法
* @params file
* @return 壓縮后的文件,支持兩種,file和 blob
*/
compressImg(file) {
const reader = new FileReader();
// readAsDataURL 方法會讀取指定的 Blob 或 File 對象。讀取操作完成的時候,readyState 會變成已完成DONE,并觸發(fā) loadend (en-US) 事件,
// 同時 result 屬性將包含一個data:URL格式的字符串(base64編碼)以表示所讀取文件的內(nèi)容。
reader.readAsDataURL(file);
reader.onload = () => {
const img = new Image();
img.src = reader.result;
img.onload = () => {
// 圖片的寬高
const w = img.width;
const h = img.height;
const canvas = document.createElement("canvas");
// canvas對圖片進行裁剪,這里設(shè)置為圖片的原始尺寸
canvas.width = w;
canvas.height = h;
const ctx = canvas.getContext("2d");
// canvas中,png轉(zhuǎn)jpg會變黑底,所以先給canvas鋪一張白底
ctx.fillStyle = "#fff";
// fillRect()方法繪制一個填充了內(nèi)容的矩形,這個矩形的開始點(左上點)在
// (x, y) ,它的寬度和高度分別由width 和 height 確定,填充樣式由當前的fillStyle 決定。
ctx.fillRect(0, 0, canvas.width, canvas.height);
// 繪制圖像
ctx.drawImage(img, 0, 0, w, h);
// canvas轉(zhuǎn)圖片達到圖片壓縮效果
// 返回一個包含圖片展示的 data URI base64 在指定圖片格式為 image/jpeg 或 image/webp的情況下,
// 可以從 0 到 1 的區(qū)間內(nèi)選擇圖片的質(zhì)量。如果超出取值范圍,將會使用默認值 0.92。其他參數(shù)會被忽略。
const dataUrl = canvas.toDataURL("image/jpeg", 0.8);
this.dialogImageUrl = dataUrl
};
};
},4、拿到的base64地址,不能直接給后端,要轉(zhuǎn)格式,這里提供兩種,一是file文件,跟壓縮前的格式一樣,還有一種是blob方法
// canvas生成的格式為base64,需要進行轉(zhuǎn)化, base64->file
dataURLtoFile(dataurl,fileName) {
let arr = dataurl.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 File([u8arr], fileName, {type:mime})
},
// canvas生成的格式為base64,需要進行轉(zhuǎn)化, base64->blob
dataURLtoBlob(dataurl) {
const arr = dataurl.split(","),
mime = arr[0].match(/:(.*?);/)[1],
bstr = atob(arr[1]);
let n = bstr.length;
const u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
return new Blob([u8arr], { type: mime });
},實現(xiàn)源碼(上傳+壓縮):
uploadImg.vue
<template>
<div class="uploadImgBody">
<!--上傳圖片部分-->
<el-upload
class="upload-image"
ref="upload"
:action="action"
:headers="headers"
:multiple="multiple"
:data="data"
:name="name"
:show-file-list="showFileList"
:drag="drag"
:accept="accept"
:list-type="listType"
:auto-upload="autoUpload"
:disabled="is_disabled"
:before-upload="beforeUpload"
>
<!--彈框展示上傳以后的圖片-->
<img
class="fileImg"
v-if="mrImgUrl"
:src="mrImgUrl"
>
<div v-else>
<i class="el-icon-plus"></i>
</div>
</el-upload>
源圖片大小:<span v-if="sourceFile.size">{{ sourceFile.size/1024 }}</span> kb
<el-button @click="compressImgFun" style="display: block;margin:10px 0;">點我壓縮</el-button>
壓縮圖片大?。?lt;span v-if="compressFile.size">{{compressFile.size/1024 }}</span> kb
<img
v-if="dialogImageUrl"
class="showImg"
:src="dialogImageUrl"
>
</div>
</template>
<script>
//element的上傳圖片,壓縮圖片組件
export default {
props:{
/**
* 自動上傳參數(shù)
* */
autoUpload:{ // 是否需要選取完自動上傳功能
type: Boolean,
default: true
},
// 默認圖片,父級傳過來 http開頭的文件
mrImgUrl:{
type: String,
default: ''
},
action:{//上傳的地址
type: String,
default: ''
},
headers: {//設(shè)置上傳的請求頭部
type:Object,
default: () => {
return {}
}
},
data: {//上傳時額外帶的參數(shù)
type:Object,
default: () => {
return {}
}
},
name:{//上傳的文件字段名
type: String,
default: 'file'
},
cookieOK:{//支持發(fā)送 cookie 憑證信息
type: Boolean,
default: true
},
/**
* 公共參數(shù)
* */
showFileList:{//是否顯示已上傳文件列表
type: Boolean,
default: false
},
drag:{//是否啟用拖拽上傳
type: Boolean,
default: false
},
accept:{//接受文件類型-圖片上傳類型-不同的格式之間以逗號隔開
type: String,
default: '.jpg,.jpeg,.png'
},
listType:{ // 文件列表的類型 - text/picture/picture-card
type: String,
default: 'picture-card'
},
fileList:{//已上傳的文件列表,
type:Array,
default: () => {
return [
{
name: 'food.jpeg',
url: 'https://fuss10.elemecdn.com/3/63/4e7f3a15429bfda99bce42a18cdd1jpeg.jpeg?imageMogr2/thumbnail/360x360/format/webp/quality/100'
}
]
}
},
is_disabled:{//是否禁止,true是禁止,false不禁止
type: Boolean,
default: false
},
multiple:{//是否可以多選
type: Boolean,
default: true
},
},
watch: {},
data() {
return {
dialogImageUrl:'',//源圖片
sourceFile:{}, //上傳后的圖片
compressFile:{} //壓縮后的圖片
}
},
methods: {
/**
* @上傳文件之前的鉤子
* @params file 圖片的file文件
* @return uploadFile 把文件發(fā)送給父級
* @tip 多選會調(diào)用多次該方法
*/
beforeUpload(file) {
this.sourceFile = file
this.$emit('uploadFile',file);
return
},
compressImgFun(){
this.compressImg(this.sourceFile)
console.log('壓縮前的圖片文件:file');
console.log(this.sourceFile);
},
/**
* @壓縮公共方法
* @params file
* @return 壓縮后的文件,支持兩種,file和 blob
*/
compressImg(file) {
const reader = new FileReader();
// readAsDataURL 方法會讀取指定的 Blob 或 File 對象。讀取操作完成的時候,readyState 會變成已完成DONE,并觸發(fā) loadend (en-US) 事件,
// 同時 result 屬性將包含一個data:URL格式的字符串(base64編碼)以表示所讀取文件的內(nèi)容。
reader.readAsDataURL(file);
reader.onload = () => {
const img = new Image();
img.src = reader.result;
img.onload = () => {
// 圖片的寬高
const w = img.width;
const h = img.height;
const canvas = document.createElement("canvas");
// canvas對圖片進行裁剪,這里設(shè)置為圖片的原始尺寸
canvas.width = w;
canvas.height = h;
const ctx = canvas.getContext("2d");
// canvas中,png轉(zhuǎn)jpg會變黑底,所以先給canvas鋪一張白底
ctx.fillStyle = "#fff";
// fillRect()方法繪制一個填充了內(nèi)容的矩形,這個矩形的開始點(左上點)在
// (x, y) ,它的寬度和高度分別由width 和 height 確定,填充樣式由當前的fillStyle 決定。
ctx.fillRect(0, 0, canvas.width, canvas.height);
// 繪制圖像
ctx.drawImage(img, 0, 0, w, h);
// canvas轉(zhuǎn)圖片達到圖片壓縮效果
// 返回一個包含圖片展示的 data URI base64 在指定圖片格式為 image/jpeg 或 image/webp的情況下,
// 可以從 0 到 1 的區(qū)間內(nèi)選擇圖片的質(zhì)量。如果超出取值范圍,將會使用默認值 0.92。其他參數(shù)會被忽略。
const dataUrl = canvas.toDataURL("image/jpeg", 0.8);
this.dialogImageUrl = dataUrl
// base64格式文件轉(zhuǎn)成Blob文件格式
let blobFile = this.dataURLtoBlob(dataUrl);
console.log("壓縮后的圖片:Blob文件----------");
console.log(blobFile);
// base64格式文件轉(zhuǎn)成file文件格式
let fileName = this.sourceFile.name
let fileImg = this.dataURLtoFile(dataUrl,fileName);
console.log("壓縮后的圖片:file文件----------");
console.log(fileImg);
this.compressFile = fileImg
};
};
},
// canvas生成的格式為base64,需要進行轉(zhuǎn)化, base64->file
dataURLtoFile(dataurl,fileName) {
let arr = dataurl.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 File([u8arr], fileName, {type:mime})
},
// canvas生成的格式為base64,需要進行轉(zhuǎn)化, base64->blob
dataURLtoBlob(dataurl) {
const arr = dataurl.split(","),
mime = arr[0].match(/:(.*?);/)[1],
bstr = atob(arr[1]);
let n = bstr.length;
const u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
return new Blob([u8arr], { type: mime });
},
},
}
</script>
<style lang='scss' scoped>
.uploadImgBody{
height: auto;
.upload-image{
width:200px;
height: 200px;
.fileImg{
width:100%;
height: 100%;
}
}
.showImg{
width:100px;
height: 100px;
}
}
</style>更多資料:
前端圖片壓縮(幾乎無損)_藍格子.的博客-CSDN博客_前端無損壓縮
到此這篇關(guān)于element前端實現(xiàn)壓縮圖片的功能的文章就介紹到這了,更多相關(guān)element 壓縮圖片內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Vue基礎(chǔ)之MVVM,模板語法和數(shù)據(jù)綁定
這篇文章主要為大家介紹了Vue之MVVM,模板語法和數(shù)據(jù)綁定,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助2021-12-12
使用typescript構(gòu)建Vue應(yīng)用的實現(xiàn)
這篇文章主要介紹了使用typescript構(gòu)建Vue應(yīng)用的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2019-08-08
Vue3源碼分析reactivity實現(xiàn)方法示例
這篇文章主要為大家介紹了Vue3源碼分析reactivity實現(xiàn)方法原理示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-01-01
Vue-CLI 3.X 部署項目至生產(chǎn)服務(wù)器的方法
這篇文章主要介紹了Vue-CLI 3.X 部署項目至生產(chǎn)服務(wù)器的方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2019-03-03
vue2 d3實現(xiàn)企查查股權(quán)穿透圖股權(quán)結(jié)構(gòu)圖效果詳解
這篇文章主要為大家介紹了vue2 d3實現(xiàn)企查查股權(quán)穿透圖股權(quán)結(jié)構(gòu)圖效果詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-01-01
vue2利用html2canvas+jspdf動態(tài)生成多頁PDF方式
利用vue2結(jié)合html2canvas和jspdf,可以實現(xiàn)前端頁面內(nèi)容導(dǎo)出為PDF的功能,首先需要安裝相關(guān)依賴,使用html2canvas將指定div內(nèi)容捕捉為圖像,再通過jspdf將圖像轉(zhuǎn)換為PDF2024-09-09
Vue echarts模擬后端數(shù)據(jù)流程詳解
在平常的項目中,echarts圖表我們也是使用的非常多的,通常我們從后端拿到數(shù)據(jù),需要在圖表上動態(tài)的進行呈現(xiàn),接下來我們就模擬從后端獲取數(shù)據(jù)然后進行呈現(xiàn)的方法2022-09-09

