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 = maxHeight
targetWidth = 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导出成为base64
this.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
// 根据解码结果字符串的长度创建一个等长的整形数字数组
// 但在创建时 所有元素初始值都为 0
const 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
时,将图片临时处理缩小后返回即可,这种操作不能影响到前端大图展示
文章仅为本人学习过程的一个记录,仅供参考,如有问题,欢迎指出!
更多推荐
已为社区贡献25条内容
所有评论(0)