前端实现图片上传及压缩功能
准备工作
在开始之前,请确保你已经具备以下环境:
- Vue项目环境
- Node环境
安装lrz
在项目目录下,运行以下命令来安装lrz库:
npm/pnpm i lrz -d
编写上传文件的HTML代码
通过input
标签并设置type
属性为file
,可以实现文件上传功能。multiple
属性允许选择多个文件进行上传。
示例代码:
<template>
<div class="container">
<input type="file" multiple @change="onFileChange" accept="image/*">
<div class="img-list">
<div class="img-item" v-for="(item, index) in imgList" :key="index">
<img :src="item.src" />
</div>
</div>
</div>
</template>
<style scoped>
.container {
width: 100%;
}
.img-list {
display: flex;
align-items: center;
gap: 4px;
}
.img-item {
width: 300px;
height: 300px;
}
img {
width: 100%;
height: 100%;
}
</style>
编写上传文件的JavaScript代码
当用户选择文件后,onFileChange
方法会被触发。lrz
是一个基于Promise的方法,可以通过async/await
进行同步处理。更多lrz
的详细用法,请访问lrz - npm。
import { ref } from 'vue';
// 导入lrz库
import lrz from "lrz";
// 用于存储压缩后的图片
const imgList = ref([]);
// 用于存储压缩后的文件列表
const fileList = ref([]);
const onFileChange = async (e) => {
const files = e.target.files;
for (let i = 0; i < files.length; i++) {
const file = files[i];
// 确保文件是图像文件
if (!file.type.startsWith('image')) continue;
console.log(`压缩前文件${i}大小为${file.size / 1024}kb`);
await lrz(file, { width: 320 }).then(res => {
const img = new Image();
img.src = res.base64;
imgList.value.push({ src: img.src });
// 压缩后的文件是Blob对象,如果需要File对象,可以进行转换
fileList.value.push(res.file);
console.log(`压缩后文件${i}大小为${res.fileLen / 1024}kb`);
});
}
};
压缩效果
通过调整lrz
中的参数,如quality
,可以获得更满意的图像压缩效果。可以看到,图片从600多kb压缩到了20多kb,效果显著。
通过Post请求将图片发送到后端
使用POST请求发送图片文件到后端,通常需要使用FormData
对象来构建请求体,因为它可以方便地处理文件和表单数据。使用formdata传输文件数据时,浏览器会自动将http请求的Content-Type
设置为 multipart/form-data
,
- 创建
FormData
实例。 - 将图片文件添加到
FormData
对象中。 - 后端将文件保存到oss或者本地。
简要代码:
const uploadImg = () => {
var params = new FormData();
fileList.value.map((item) => {
// files 修改为后端要求的变量名
params.append("files", item);
});
// 发送请求到后端的具体逻辑
axios.post("后端上传文件的url",params).then(res=>{})
};
最后给出完整代码:
<script setup>
import { ref } from 'vue';
import lrz from "lrz"
const imgList = ref([])
const fileList = ref([])
const onFileChange =async (e) => {
const files = e.target.files
for (let i = 0; i < files.length; i++) {
const file = files[i]
// 判断是否为图像文件
if(file.type.indexOf('image') !== 0) continue
console.log(`压缩前文件${i} 大小为${file.size/1024}kb`)
await lrz(file,{width:320}).then(res=>{
var img = new Image()
img.src = res.base64
imgList.value.push(img)
// 此时fileList的文件是Blob对象,如果上传文件需要File对象需要转换一下类型
// 将压缩后的 Blob 转换为 File
// const compressedFile = new File([rst.file], file.name, { type: file.type });
fileList.value.push(res.file)
console.log(`压缩后文件${i} 大小为${res.fileLen/1024}kb`)
})
}
}
</script>
<template>
<div class="container">
<input type="file" multiple @change="onFileChange" accept="image/*">
<div class="img-list">
<div class="img-item">
<img v-for="(item,index) in imgList" :key="index" :src="item.src"/>
</div>
</div>
</div>
</template>
<style scoped>
.container {
width: 100%;
}
.img-list {
display: flex;
align-items: center;
gap: 4px;
}
.img-item {
width: 300px;
height: 300px;
}
img {
width: 100%;
height: 100%;
}
</style>