vue + el-upload 实现图片尺寸缩小
一、背景
前端对图片进行 剪裁 或者 大小进行压缩 都是比较场景的需求。但是这次接到一个 将图片尺寸缩小 的需求,为啥呢?因为在前端上传到服务器后,有个功能会导出 word,而图片就会放到里面去导出,而图片尺寸太大,显示会有问题;例如简历个人信息里面的身份证、学历、头像等照片(这种问题其实我觉得应该由后端处理,但既然知道了,就研究研究)。
二、实现思路
有个问题需要先确定:缩放实现在上传前还是上传后,区别是什么?
el-upload组件中一般都有大图预览功能,即el-image 中的预览功能previewSrcList;
- 上传前缩小:保存后的图片较小,预览大图也不能看到原始尺寸(没保存前可以看到)
- 上传后缩小:需要上传两张图,并且小图需要做无感上传,原始图和缩小后的图片,并且需要定义区分规则,怎么获取大图,怎么获取小图
由于项目中对大图展示要求不高,故采用 上传前缩小 实现;
三、代码实现
el-upload 二次封装代码不尽相同,故在此只展现压缩相关核心代码
compressImgSize(file) { // 压缩图片// file 里面没有url 字段(el-upload自带,用于图片展示的临时路径),则通过URL.createObjectURL(file)转化为临时路径// const fileUrl = URL.createObjectURL(file)// const image = new Image();// image.src = fileUrl;const image = new Image();image.src = file.url;image.onload = (e) => { // onload 才能获取到图片真实的宽高console.log('image.width', image, image.width, image.height)if (image.width > 0 && image.height > 0) {const oldScale = Number((image.width / image.height).toFixed(2));let maxWidth = 200, maxHeight = 200; // 定义缩放后的最大宽高let targetWidth = image.width, targetHeight = image.height; // 图片缩放后的真实宽高, 默认为图片的原始尺寸if (targetWidth > maxWidth) { // 目标宽度大于最大宽度targetWidth = maxWidth;targetHeight = targetWidth / oldScale;}//缩放后高度仍然大于最大高度继续按比例缩小if (targetHeight > maxHeight) {targetHeight = maxHeighttargetWidth = targetHeight * oldScale;}const canvas = document.createElement('canvas'); // 创建一个canvas节点const context = canvas.getContext('2d');canvas.width = targetWidth; // 设置canvas的宽高canvas.height = targetHeight;context.drawImage(image, 0, 0, targetWidth, targetHeight); // 将图片绘制到canvas内部const imageBase64 = canvas.toDataURL('image', 0.92);//canvas导出成为base64this.upData.file = this.base64ToFile(imageBase64, 'file') // 将base64图片转为 file 对象this.$refs.upload.submit(); // 触发上传}}},// base64图片转file的方法(base64图片, 设置生成file的文件名)
base64ToFile(base64, fileName) {// 将base64按照 , 进行分割 将前缀 与后续内容分隔开let data = base64.split(',');// 利用正则表达式 从前缀中获取图片的类型信息(image/png、image/jpeg、image/webp等)let type = data[0].match(/:(.*?);/)[1];// 从图片的类型信息中 获取具体的文件格式后缀(png、jpeg、webp)let suffix = type.split('/')[1];// 使用atob()对base64数据进行解码 结果是一个文件数据流 以字符串的格式输出const bstr = window.atob(data[1]);// 获取解码结果字符串的长度let n = bstr.length// 根据解码结果字符串的长度创建一个等长的整形数字数组// 但在创建时 所有元素初始值都为 0const u8arr = new Uint8Array(n)// 将整形数组的每个元素填充为解码结果字符串对应位置字符的UTF-16 编码单元while (n--) {// charCodeAt():获取给定索引处字符对应的 UTF-16 代码单元u8arr[n] = bstr.charCodeAt(n)}// 利用构造函数创建File文件对象// new File(bits, name, options)const file = new File([u8arr], `${fileName}.${suffix}`, {type: type})// 将File文件对象返回给方法的调用者return file;
}
注意点:
- compressImgSize 压缩方法调用位置在
上传文件之前的钩子 before-upload或者是文件状态改变时的钩子 on-change 上传文件之前的钩子 before-upload拿到的file没有url,需要通过URL.createObjectURL(file)转化文件状态改变时的钩子 on-change里面有临时路径 url,可直接使用this.$refs.upload.submit()手动触发的上传方法,文件默认还是原始图片,需要通过配置data: { file: this.upData.fil } => 上传时附带的额外参数实现上传缩小后的图片;但el-upload默认在上传时携带了file参数并不可删除(但是可以用过配置name: "oldFile"去修改,保证后端不再使用到,查阅el-upload源码可知,文档没有),所以可以通过配置name="file2"将原本的file => 修改成file2即可。
ps:
最佳方式还是由后端重新写一个 接口A,在导出接口中调用 接口A 时,将图片临时处理缩小后返回即可,这种操作不能影响到前端大图展示
文章仅为本人学习过程的一个记录,仅供参考,如有问题,欢迎指出!
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
