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


Posted in Javascript onJanuary 15, 2020

本文主要讲解基于 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 左右。此时判断压缩后比压缩前小,上传压缩图到服务器。

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

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

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

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

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

总结

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

Javascript 相关文章推荐
MC Dialog js弹出层 完美兼容多浏览器(5.6更新)
May 06 Javascript
jQuery 淡入淡出 png图在ie8下有黑色边框的解决方法
Mar 05 Javascript
jQuery中nextAll()方法用法实例
Jan 07 Javascript
jQuery实现点击小图片淡入淡出显示大图片特效
Sep 09 Javascript
AngularJS中如何使用$parse或$eval在运行时对Scope变量赋值
Jan 25 Javascript
js不间断滚动的简单实现
Jun 03 Javascript
JS获取当前页面名称的简单实例
Aug 19 Javascript
基于JavaScript定位当前的地理位置
Apr 11 Javascript
详解webpack 多入口配置
Jun 16 Javascript
React-Native 组件之 Modal的使用详解
Aug 08 Javascript
浅谈vue方法内的方法使用this的问题
Sep 15 Javascript
微信小程序防止多次点击跳转和防止表单组件输入内容多次验证功能(函数防抖)
Sep 19 Javascript
JS函数进阶之继承用法实例分析
Jan 15 #Javascript
JS函数进阶之prototy用法实例分析
Jan 15 #Javascript
JS函数基本定义与用法示例
Jan 15 #Javascript
JS几个常用的函数和对象定义与用法示例
Jan 15 #Javascript
JS自定义对象创建与简单使用方法示例
Jan 15 #Javascript
vue移动端使用canvas签名的实现
Jan 15 #Javascript
js实现鼠标拖拽div左右滑动
Jan 15 #Javascript
You might like
3
2006/10/09 PHP
php socket方式提交的post详解
2008/07/19 PHP
使用PHP socke 向指定页面提交数据
2008/07/23 PHP
php 将字符串按大写字母分隔成字符串数组
2010/04/30 PHP
php函数array_merge用法一例(合并同类数组)
2013/02/03 PHP
验证token、回复图文\文本、推送消息的实用微信类php代码
2016/06/28 PHP
让ThinkPHP的模板引擎达到最佳效率的方法详解
2017/03/14 PHP
在html页面上拖放移动标签
2010/01/08 Javascript
基于Jquery的文字滚动跑马灯插件(一个页面多个滚动区)
2010/07/26 Javascript
jquery图片不完全按比例自动缩小的简单代码
2013/07/29 Javascript
利用Keydown事件阻止用户输入实现代码
2014/03/11 Javascript
JavaScript学习心得之概述
2015/01/20 Javascript
vue-cli + sass 的正确打开方式图文详解
2017/10/27 Javascript
Angular使用过滤器uppercase/lowercase实现字母大小写转换功能示例
2018/03/27 Javascript
React Component存在的几种形式详解
2018/11/06 Javascript
Vue data的数据响应式到底是如何实现的
2020/02/11 Javascript
JS数组的高级使用方法示例小结
2020/03/14 Javascript
微信小程序之滑动页面隐藏和显示组件功能的实现代码
2020/06/19 Javascript
Vant 在vue-cli 4.x中按需加载操作
2020/11/05 Javascript
python 实现归并排序算法
2012/06/05 Python
Python使用函数默认值实现函数静态变量的方法
2014/08/18 Python
python类的方法属性与方法属性的动态绑定代码详解
2017/12/27 Python
解决Django数据库makemigrations有变化但是migrate时未变动问题
2018/05/30 Python
python利用openpyxl拆分多个工作表的工作簿的方法
2019/09/27 Python
详解Python实现进度条的4种方式
2020/01/15 Python
Python类的动态绑定实现原理
2020/03/21 Python
ipython jupyter notebook中显示图像和数学公式实例
2020/04/15 Python
Django之腾讯云短信的实现
2020/06/12 Python
python温度转换华氏温度实现代码
2020/12/06 Python
英语自我评价范文
2014/01/24 职场文书
工业自动化专业自荐信范文
2014/04/10 职场文书
2014年学校禁毒工作总结
2014/12/23 职场文书
小学四年级学生评语
2014/12/26 职场文书
师德承诺书2015
2015/04/28 职场文书
2015年小学总务工作总结
2015/07/21 职场文书
高中班主任培训心得体会
2016/01/07 职场文书