前端实现图片上传及压缩功能

751 阅读2分钟

前端实现图片上传及压缩功能

准备工作

在开始之前,请确保你已经具备以下环境:

  • 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`);
    });
  }
};

压缩效果

image.png

通过调整lrz中的参数,如quality,可以获得更满意的图像压缩效果。可以看到,图片从600多kb压缩到了20多kb,效果显著。

通过Post请求将图片发送到后端

使用POST请求发送图片文件到后端,通常需要使用FormData对象来构建请求体,因为它可以方便地处理文件和表单数据。使用formdata传输文件数据时,浏览器会自动将http请求的Content-Type 设置为 multipart/form-data

  1. 创建FormData实例。
  2. 将图片文件添加到FormData对象中。
  3. 后端将文件保存到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>