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 相关文章推荐
豆瓣网的jquery代码实例
Jun 15 Javascript
javascript 按回车键相应按钮提交事件
Nov 02 Javascript
jQuery中:input选择器用法实例
Jan 03 Javascript
原生js和jQuery实现淡入淡出轮播效果
Dec 25 Javascript
利用Node.js对文件进行重命名
Mar 12 Javascript
简单实现JS上传图片预览功能
Apr 14 Javascript
js获取css的各种样式并且设置他们的方法
Aug 22 Javascript
判断文字超过2行添加展开按钮,未超过则不显示,溢出部分显示省略号
Apr 28 Javascript
vue cli安装使用less的教程详解
Jul 12 Javascript
JavaScript判断浏览器版本的方法
Nov 03 Javascript
详解Vue中的MVVM原理和实现方法
Jul 15 Javascript
javascript实现点击产生随机图形
Jan 25 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
GBK的页面输出JSON格式的php函数
2010/02/16 PHP
需要注意的几个PHP漏洞小结
2012/02/05 PHP
ThinkPHP连接数据库及主从数据库的设置教程
2014/08/22 PHP
thinkphp中session和cookie无效的解决方法
2014/12/19 PHP
CI框架中数据库操作函数$this-&gt;db-&gt;where()相关用法总结
2016/05/17 PHP
WordPress中的shortcode短代码功能使用详解
2016/05/17 PHP
多浏览器兼容的获取元素和鼠标的位置的js代码
2009/12/15 Javascript
面向对象的Javascript之二(接口实现介绍)
2012/01/27 Javascript
jquery制作LED 时钟特效
2015/02/01 Javascript
关注jquery技巧提高jquery技能(前端开发必学)
2015/11/02 Javascript
node.js回调函数之阻塞调用与非阻塞调用
2015/11/13 Javascript
原生JS实现图片翻书效果
2017/02/16 Javascript
js 实现省市区三级联动菜单效果
2017/02/20 Javascript
Thinkphp5微信小程序获取用户信息接口的实例详解
2017/09/26 Javascript
vue.js 嵌套循环、if判断、动态删除的实例
2018/03/07 Javascript
vue实现简单的星级评分组件源码
2018/11/16 Javascript
Angular使用Restful的增删改
2018/12/28 Javascript
关于layui的下拉搜索框异步加载数据的解决方法
2019/09/28 Javascript
修改NPM全局模式的默认安装路径的方法
2020/12/15 Javascript
[01:04:05]Mineski vs TNC 2019国际邀请赛小组赛 BO2 第一场 8.15
2019/08/16 DOTA
Python中实现结构相似的函数调用方法
2015/03/10 Python
python字符串过滤性能比较5种方法
2017/06/22 Python
TensorFlow索引与切片的实现方法
2019/11/20 Python
python代码区分大小写吗
2020/06/17 Python
关于Python 解决Python3.9 pandas.read_excel(‘xxx.xlsx‘)报错的问题
2020/11/28 Python
Python将QQ聊天记录生成词云的示例代码
2021/02/10 Python
英国最大的宠物食品和宠物用品网上零售商: Zooplus
2016/08/01 全球购物
Roxy荷兰官方网站:冲浪、滑雪板、服装和配件
2019/10/22 全球购物
优质的学校老师推荐信
2013/10/28 职场文书
预备党员党校学习自我评价分享
2013/11/12 职场文书
幼儿园消防安全制度
2014/01/26 职场文书
乡镇爱国卫生月活动总结
2014/06/25 职场文书
习近平在党的群众路线教育实践活动总结大会上的讲话全文
2014/10/25 职场文书
先进班组事迹材料
2014/12/25 职场文书
2015高三毕业寄语赠言
2015/02/27 职场文书
2015年幼儿园保育工作总结
2015/05/12 职场文书