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类
Sep 08 Javascript
JS 巧妙获取剪贴板数据 Excel数据的粘贴
Jul 09 Javascript
JS判断元素为数字的奇异写法分享
Aug 01 Javascript
随窗体滑动的小插件sticky源码
Jun 21 Javascript
JS实现拖动示例代码
Nov 01 Javascript
javascript 应用小技巧方法汇总
Jul 05 Javascript
JQuery+Ajax实现数据查询、排序和分页功能
Sep 27 Javascript
jquery在ie7下选择器的问题导致append失效的解决方法
Jan 10 Javascript
Angular懒加载机制刷新后无法回退的快速解决方法
Aug 30 Javascript
JS用斜率判断鼠标进入DIV四个方向的方法
Nov 07 Javascript
Vue表单之v-model绑定下拉列表功能
May 14 Javascript
JavaScript对象属性操作实例解析
Feb 04 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 友好URL的实现(吐血推荐)
2008/10/04 PHP
PHP操作mysql函数详解,mysql和php交互函数
2011/05/19 PHP
php文件下载处理方法分析
2015/04/22 PHP
WordPress中用于更新伪静态规则的PHP代码实例讲解
2015/12/18 PHP
Zend Framework入门教程之Zend_Config组件用法详解
2016/12/09 PHP
PHP字典树(Trie树)定义与实现方法示例
2017/10/09 PHP
让GoogleCode的SVN下的HTML文件在FireFox下正常显示.
2009/05/25 Javascript
javascript各浏览器中option元素的表现差异
2011/04/07 Javascript
基于jquery实现后台左侧菜单点击上下滑动显示
2013/04/11 Javascript
js原生appendChild的bug解决心得分享
2013/07/01 Javascript
node.js中的fs.link方法使用说明
2014/12/15 Javascript
JavaScript实现将xml转换成html table表格的方法
2015/04/17 Javascript
百度搜索框智能提示案例jsonp
2016/11/28 Javascript
javascript 开发之百度地图使用到的js函数整理
2017/05/19 Javascript
Express + Node.js实现登录拦截器的实例代码
2017/07/01 Javascript
JS实现按钮添加背景音乐示例代码
2017/10/17 Javascript
JS实现的JSON数组去重算法示例
2018/04/11 Javascript
BootStrap表单验证中的非Submit类型按钮点击时触发验证的坑
2019/09/05 Javascript
解析vue、angular深度作用选择器
2019/09/11 Javascript
Js逆向实现滑动验证码图片还原的示例代码
2020/03/10 Javascript
vue项目实现减少app.js和vender.js的体积操作
2020/11/12 Javascript
vue开发chrome插件,实现获取界面数据和保存到数据库功能
2020/12/01 Vue.js
python返回昨天日期的方法
2015/05/13 Python
python删除指定类型(或非指定)的文件实例详解
2015/07/06 Python
简述Python2与Python3的不同点
2018/01/21 Python
python判断完全平方数的方法
2018/11/13 Python
在python中使用xlrd获取合并单元格的方法
2018/12/26 Python
如何基于Python制作有道翻译小工具
2019/12/16 Python
python学生信息管理系统实现代码
2019/12/17 Python
美国浴缸、水槽和水龙头购物网站:Vintage Tub & Bath
2019/11/05 全球购物
欧姆龙医疗欧洲有限公司:Omron Healthcare Europe B.V
2020/06/13 全球购物
英国鲜花递送:Blossoming Gifts
2020/07/10 全球购物
介绍一下Transact-SQL中SPACE函数的用法
2015/09/01 面试题
2014年派出所工作总结
2014/11/21 职场文书
Python图像处理之图像拼接
2021/04/28 Python
Win11怎么添加用户?Win11添加用户账户的方法
2022/07/15 数码科技