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 相关文章推荐
防止页面被iframe(兼容IE,Firefox火狐)
Jul 04 Javascript
Jquery+ajax请求data显示在GridView上(asp.net)
Aug 27 Javascript
图片onload事件触发问题解决方法
Jul 31 Javascript
JS 控件事件小结
Oct 31 Javascript
得到form下的所有的input的js代码
Nov 07 Javascript
使用js完成节点的增删改复制等的操作
Jan 02 Javascript
用jquery等比例控制图片宽高的具体实现
Jan 28 Javascript
解决vue 格式化银行卡(信用卡)每4位一个符号隔断的问题
Sep 14 Javascript
vue2 v-model/v-text 中使用过滤器的方法示例
May 09 Javascript
封装微信小程序http拦截器过程解析
Aug 13 Javascript
解决vue组件没显示,没起作用,没报错,但该显示的组件没显示问题
Sep 02 Javascript
JavaScript常用工具函数汇总(浏览器环境)
Sep 17 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循环检测目录是否存在并创建(循环创建目录)
2011/01/06 PHP
PHP基于单例模式编写PDO类的方法
2016/09/13 PHP
TP3.2批量上传文件或图片 同名冲突问题的解决方法
2017/08/01 PHP
tp5.0框架隐藏index.php入口文件及模块和控制器的方法分析
2020/02/11 PHP
网页中的图片的处理方法与代码
2009/11/26 Javascript
Javascript公共脚本库系列(一): 弹出层脚本
2011/02/24 Javascript
简单的前端js+ajax 购物车框架(入门篇)
2011/10/29 Javascript
网站基于flash实现的Banner图切换效果代码
2014/10/14 Javascript
JSP基于Bootstrap分页显示实例解析
2016/06/12 Javascript
标准的js无缝滚动效果
2016/08/30 Javascript
BootStrap Validator 版本差异问题导致的submitHandler失效问题的解决方法
2016/12/01 Javascript
AngularJS select加载数据选中默认值的方法
2018/02/28 Javascript
js中Array对象的常用遍历方法详解
2019/01/17 Javascript
JavaScript一元正号运算符示例代码
2019/06/30 Javascript
VUE DEMO之模拟登录个人中心页面之间数据传值实例
2019/10/31 Javascript
Vue的props父传子的示例代码
2020/05/20 Javascript
Vue.js中使用Vuex实现组件数据共享案例
2020/07/31 Javascript
design vue 表格开启列排序的操作
2020/10/28 Javascript
nuxt 自定义 auth 中间件实现令牌的持久化操作
2020/11/05 Javascript
Python通过matplotlib画双层饼图及环形图简单示例
2017/12/15 Python
Python字典创建 遍历 添加等实用基础操作技巧
2018/09/13 Python
Python Pandas 箱线图的实现
2019/07/23 Python
Django框架 查询Extra功能实现解析
2019/09/04 Python
Pandas时间序列基础详解(转换,索引,切片)
2020/02/26 Python
解决pytorch 交叉熵损失输出为负数的问题
2020/07/07 Python
浅析Python 序列化与反序列化
2020/08/05 Python
Python 可视化神器Plotly详解
2020/12/26 Python
Lee牛仔裤澳大利亚官网:美国著名牛仔裤品牌
2017/09/02 全球购物
Linux面试经常问的文件系统操作命令
2015/11/05 面试题
学校党委干部个人对照检查材料思想汇报
2014/10/09 职场文书
2015年教师节活动总结
2015/03/20 职场文书
2015年幼儿园班务工作总结
2015/05/12 职场文书
债务追讨律师函
2015/06/24 职场文书
使用pycharm运行flask应用程序的详细教程
2021/06/07 Python
《进击的巨人》新联动CM 兵长强势出击兽巨人
2022/04/05 日漫
python绘制云雨图raincloud plot
2022/08/05 Python