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 相关文章推荐
javascript sudoku 数独智力游戏生成代码
Mar 27 Javascript
40个有创意的jQuery图片和内容滑动及弹出插件收藏集之三
Jan 03 Javascript
使用js判断数组中是否包含某一元素(类似于php中的in_array())
Dec 12 Javascript
jQuery学习笔记之 Ajax操作篇(二) - 数据传递
Jun 23 Javascript
jQuery中attr()和prop()在修改checked属性时的区别
Jul 18 Javascript
js实现的倒计时按钮实例
Jun 24 Javascript
canvas绘制的直线动画
Jan 23 Javascript
微信小程序封装http访问网络库实例代码
May 24 Javascript
vue实现商城上货组件简易版
Nov 27 Javascript
AngularJS使用Filter自定义过滤器控制ng-repeat去除重复功能示例
Apr 21 Javascript
vue 自定义指令自动获取文本框焦点的方法
Aug 25 Javascript
微信小程序数据统计和错误统计的实现方法
Jun 26 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
php 多线程上下文中安全写文件实现代码
2009/12/28 PHP
一步一步学习PHP(2)――PHP类型
2010/02/15 PHP
php如何实现只替换一次或N次
2015/10/29 PHP
jquery 全局AJAX事件使用代码
2010/11/05 Javascript
ExtJs的Date格式字符代码
2010/12/30 Javascript
JS事件在IE与FF中的区别详细解析
2013/11/20 Javascript
简单的jquery左侧导航栏和页面选中效果
2014/08/21 Javascript
jQuery实现表格行和列的动态添加与删除方法【测试可用】
2016/08/01 Javascript
轻松掌握JavaScript享元模式
2016/08/27 Javascript
深入理解javascript函数参数与闭包
2016/12/12 Javascript
BootStrap实现轮播图效果(收藏)
2016/12/30 Javascript
Angular2安装angular-cli
2017/05/21 Javascript
使用classList来实现两个按钮样式的切换方法
2018/01/24 Javascript
JS跨域请求的问题解析
2018/12/03 Javascript
Python的装饰器使用详解
2017/06/26 Python
Python进度条实时显示处理进度的示例代码
2018/01/30 Python
Python  unittest单元测试框架的使用
2018/09/08 Python
用pycharm开发django项目示例代码
2018/10/24 Python
PyQt5实现从主窗口打开子窗口的方法
2019/06/19 Python
春节到了 教你使用python来抢票回家
2020/01/06 Python
python爬虫模块URL管理器模块用法解析
2020/02/03 Python
卡塔尔航空官方网站:Qatar Airways
2017/02/08 全球购物
Annoushka英国官网:英国奢侈珠宝品牌
2018/10/20 全球购物
大学生专科学习生活的自我评价
2013/12/07 职场文书
厂长助理岗位职责
2013/12/27 职场文书
留学推荐信怎么写
2014/01/25 职场文书
计算机大学生职业生涯规划书范文
2014/02/19 职场文书
机关党员三严三实心得体会
2014/10/13 职场文书
大学学生个人总结
2015/02/15 职场文书
心灵捕手观后感
2015/06/02 职场文书
2015年高三年级组工作总结
2015/07/21 职场文书
2016幼儿园新学期寄语
2015/12/03 职场文书
计算机实训心得体会
2016/01/14 职场文书
小学运动会开幕词
2016/03/04 职场文书
Anaconda配置各版本Pytorch的实现
2021/08/07 Python
详解Golang如何优雅的终止一个服务
2022/03/21 Golang