vue3實現原生上傳圖片並壓縮為base64后,轉成二進制文件,實現預覽
<template>
<template>
<div @click="chooseImg">上傳</div>
<div v-for="(item, index) in imgUrls" :key="index" >
<img :src="item.src" />
</div>
</template>
script
interface STATE {
imgUrls: Array<{
id: string;
src: string;
}>;
}
export default {
name: "Index",
setup() {
const state = reactive<STATE>({
imgUrls: [], // 上傳的圖片展示列表
});
/** 選擇圖片 */
const chooseImg = () => {
let inputUploadObj: any = document.createElement("input");
inputUploadObj.setAttribute("id", "input_upload_ID");
inputUploadObj.setAttribute("type", "file");
// 添加這個屬性,就可以喚起相機的功能
// inputUploadObj.setAttribute("capture", "user"); // 后置攝像頭:camcorder 前置攝像頭:user
// 這里如果不加屬性 accept 是 "image/*" 或者 "video/*",就默認打開攝像頭,既可以拍照也可以錄像
inputUploadObj.setAttribute("accept", "image/*");
inputUploadObj.setAttribute("style", "visibility:hidden");
// 這里將創建的隱式input控件拼接到body的最后面,會增加頁面的長度,所以要在適當的時候,移除掉這個隱式創建的input控件
document.body.appendChild(inputUploadObj);
// 這里是模擬點擊了input控件
inputUploadObj.click();
// console.log(inputUploadObj.files[0])
inputUploadObj.onchange = () => {
uploadImg(inputUploadObj.files[0]);
}
};
// 將文件轉成img對象
const readImg = function (file) {
return new Promise((resolve, reject) => {
const img = new Image();
const reader = new FileReader();
reader.onload = function (e: any) {
img.src = e.target.result;
};
reader.onerror = function (e) {
reject(e);
};
reader.readAsDataURL(file);
img.onload = function () {
resolve(img);
};
img.onerror = function (e) {
reject(e);
};
});
};
/**
* 壓縮圖片
*@param img 被壓縮的img對象
* @param type 壓縮后轉換的文件類型
* @param mx 觸發壓縮的圖片最大寬度限制
* @param mh 觸發壓縮的圖片最大高度限制
*/
const compressImg = (img, type, mx, mh): any => {
const canvas = document.createElement("canvas");
const context = canvas.getContext("2d");
const { width: originWidth, height: originHeight } = img;
// 最大尺寸限制
const maxWidth = mx;
const maxHeight = mh;
// 目標尺寸
let targetWidth = originWidth;
let targetHeight = originHeight;
if (originWidth > maxWidth || originHeight > maxHeight) {
if (originWidth / originHeight > 1) {
// 寬圖片
targetWidth = maxWidth;
targetHeight = Math.round(maxWidth * (originHeight / originWidth));
} else {
// 高圖片
targetHeight = maxHeight;
targetWidth = Math.round(maxHeight * (originWidth / originHeight));
}
}
canvas.width = targetWidth;
canvas.height = targetHeight;
if (context) {
context.clearRect(0, 0, targetWidth, targetHeight);
// 圖片繪制
context.drawImage(img, 0, 0, targetWidth, targetHeight);
}
return canvas.toDataURL(type || "image/jpeg", 0.5);
};
// base64 轉二進制
const dataURLtoFile = (dataurl, filename) => {
//將base64轉換為文件
var 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,
});
}
// 隨機數
const randomNum = ()=>{
var Num="";
for(var i=0;i<13;i++)
{
Num+=Math.floor(Math.random()*10);
}
return Num
}
}
// 上傳圖片
const uploadImg = async (file) => {
const img = await readImg(file);
const blob = compressImg(img, file.type, 1000, 1000);
state.imgUrls.push({
id: randomNum(),
src: blob,
});
let formdata = new FormData();
formdata.append("file", dataURLtoFile(blob,"file-"+randomNum()));
// 上傳圖片接口調用
}
return {
...toRefs(state),
chooseImg
}
}
