Vue 图片压缩并上传至服务器功能

 更新时间:2020年01月15日 11:35:04   作者:solocoder  
这篇文章主要介绍了Vue 图片压缩并上传至服务器功能,本文通过实例代码给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下

本文主要讲解基于 Vue + Vant ,实现移动端图片选择,并用 Canvas 压缩图片,最后上传至服务器。还会封装一个工具类,方便直接调用。

一、工具类封装

废话不多说先上代码,封装一个 CompressImageUtils 工具类:

**
 * 图片压缩工具类
 * 最大高度和最大宽度都为 500,如果超出大小将等比例缩放。
 *
 * 注意可能出现压缩后比原图更大的情况,在调用的地方自己判断大小并决定上传压缩前或压缩后的图到服务器。
 */
// 将base64转换为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)) {
     // 更加严重的高窄型,确定最大高,压缩宽度
     compressedHeight = maxHeight
     compressedWidth = maxHeight * (originWidth / originHeight)
    } else {
     //更加严重的矮宽型, 确定最大宽,压缩高度
     compressedWidth = maxWidth
     compressedHeight = maxWidth * (originHeight / originWidth)
    }
   } else if (originWidth > maxWidth && originHeight <= maxHeight) {
    // 更宽,但比较矮,以maxWidth作为基准
    compressedWidth = maxWidth
    compressedHeight = maxWidth * (originHeight / originWidth)
   } else if (originWidth <= maxWidth && originHeight > maxHeight) {
    // 比较窄,但很高,取maxHight为基准
    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);
   // 回调函数返回blob的值。也可根据自己的需求返回base64的值
   resolve(blob)
  }
 })
}

定义的最大宽度和最大高度均为 500,如果图片的宽高至少有一个超出了 500,都会被 **等比例 **压缩,不用担心变形。可以根据自己项目需要改变 maxWidth 和  maxHeight 。

这里直接把压缩的最大高度和最大宽度写死为 500 了,没有在调用时传。因为一个项目压缩的逻辑和大小一般都一致的,没必要在每次调用的时候传。当然如果想写的灵活一点,可以在 compressImage 方法里再把 maxWidth 、 maxHeight 和压缩质量传上。

compressImage 方法返回的是 blob 值,根据服务端接口需要可以改为返回 base64,只需将 resolve(blob) 改为 resolve(base64) 即可。

注意一点,对于有些宽高没到 500,且分辨率很小的图片,压缩之后可能比之前还大。猜测可能是 canvas 生成的图片分辨率要比原来高一些,所以最终的图片比压缩前更大。可以在调用的地方加个判断,如果压缩完的大小比原图小,就上传压缩后的图片;如果如果压缩完的大小比原图大,就上传原图。

二、如何使用

将 CompressImageUtils 引入到目标文件,然后调用  compressImage 方法,即可在回调里获得压缩后的结果。注意  compressImage 方法返回的是 Promise。

省略其他无关代码,只保留跟压缩图片和上传相关的:

<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('压缩后的结果', result); // result即为压缩后的结果
     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>

在返回结果中加了层判断,压缩后比原来更大,则将原图上传;压缩后比原来小,上传压缩后的。解决压缩后比原图更大的情况。

this.$api.uploadImage(params) 是调用封装的 api 方法,如下:

//上传图片
 uploadImage(params){
  return axios.post(`${base}/api/v1/file`, params, {
   headers: {'content-type': 'multipart/form-data'}
  })
 },

三、使用效果

先上传一个非常大的,尺寸为 6016 × 4016,16.8M 的大图,看输出日志,压缩后大小仅为 260k 左右。此时判断压缩后比压缩前小,上传压缩图到服务器。

 

再看个尺寸 300 × 300,12k 的小图,压缩前大小是 11252,压缩后大小是 93656,大了很多。此时判断压缩后比压缩前更大,上传的是原图。

 

总结:这个工具类对大图的压缩效果很明显,不管多大的图,压缩之后基本不会超过 300k。但对某些小图可能出现压缩完反而更大的情况。在调用的地方加层压缩后和压缩前大小的比较判断,会完美解决这个问题。

当然也可以在工具类内部判断,但个人觉得跟业务逻辑相关的代码还是不要放在公用的工具类比较好。

总结

以上所述是小编给大家介绍的Vue 图片压缩并上传至服务器功能,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对脚本之家网站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!

相关文章

  • vue3学习笔记之自定义组件举例

    vue3学习笔记之自定义组件举例

    这篇文章主要给大家介绍了关于vue3学习笔记之自定义组件的相关资料,组件系统是Vue.js其中一个重要的概念,它提供了一种抽象,让我们可以使用独立可复用的小组件来构建大型应用,需要的朋友可以参考下
    2023-08-08
  • vue单应用在ios系统中实现微信分享功能操作

    vue单应用在ios系统中实现微信分享功能操作

    这篇文章主要介绍了vue单应用在ios系统中实现微信分享功能操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-09-09
  • vue前端img访问鉴权后端进行拦截的代码示例

    vue前端img访问鉴权后端进行拦截的代码示例

    路由拦截是一种在用户访问特定页面之前对其进行拦截和处理的机制,下面这篇文章主要给大家介绍了关于vue前端img访问鉴权后端进行拦截的相关资料,需要的朋友可以参考下
    2024-03-03
  • vue router如何实现tab切换

    vue router如何实现tab切换

    这篇文章主要介绍了vue router如何实现tab切换,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-04-04
  • vue实现表格合并功能

    vue实现表格合并功能

    这篇文章主要为大家详细介绍了vue实现表格合并功能,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-12-12
  • vue实现拖动调整左右两侧容器大小

    vue实现拖动调整左右两侧容器大小

    这篇文章主要为大家详细介绍了vue实现拖动调整左右两侧容器大小,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-03-03
  • vue-calendar-component 封装多日期选择组件的实例代码

    vue-calendar-component 封装多日期选择组件的实例代码

    这篇文章主要介绍了vue-calendar-component 封装多日期选择组件,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-12-12
  • vue .sync修饰符的使用详解

    vue .sync修饰符的使用详解

    这篇文章主要介绍了vue .sync修饰符的使用,本文给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2018-06-06
  • Vue 与 Vuex 的第一次接触遇到的坑

    Vue 与 Vuex 的第一次接触遇到的坑

    在 Vue.js 的项目中,如果项目结构简单, 父子组件之间的数据传递可以使用 props 或者 $emit 等方式,如果是大型项目,很多时候都需要在子组件之间传递数据,使用vue的状态管理工具vuex很好的解决
    2018-08-08
  • vue中百度地图定位及附近搜索功能使用步骤

    vue中百度地图定位及附近搜索功能使用步骤

    这篇文章主要为大家介绍了vue中百度地图定位及附近搜索功能使用步骤详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-09-09

最新评论