业务场景
场景描述:前端使用<input type="file">
标签进行上传图片时,当图片过大时,会造成接口响应速度过慢,影响用户体验。
解决方案:前端先对图片进行压缩,然后将压缩后的图片传给后端。
技术实现
我在项目里使用的是localResizeIMG(lrz)这个库,不过这个库已经很久没有维护了,介意者勿用。
-
localResizeIMG(lrz)
插件的使用方法及属性:
lrz(file,{
width:800, //设置图片压缩后的最大宽度,默认为原图宽度
height:600, //同上
quality:0.7, //图片压缩质量,取值 0 - 1,默认为 0.7
fieldName:"aijquery" //后端接收的字段名,默认:file,一般不用这项,我们要上传数据的话,可以自定义FormData对象
}).then(function(rst){
rst.formData //后端可处理的数据
rst.file //压缩后的file对象,如果压缩率太低,将会是原始file对象
rst.fileLen //压缩后的图片的大小,
rst.base64 //生成后的图片base64,后端可以处理此字符串为图片,也可以直接用于 img.src = base64
rst.base64Len //生成后的base64的大小,后端可以通过此值来校验是否传输完整
rst.origin //原始的file对象,里面存放了一些原始文件的信息,例如大小、日期等
}).catch(function(err){ //处理失败后执行
}).always(function(){ //必然执行
});
- 项目中使用情况:
HTML部分
<input type="file" @change="chooseFile">
JS部分
后端限传1M图片,所以针对压缩比例根据不同大小的图片做了对比,如代码。
async chooseFile (e) {
let file = e.target.files[0]
if (file) {
let size
let formData = new FormData()
if (file.type.indexOf('image') !== -1) { // 图片压缩
size = file.size
let quality
if (size > 1048576 && size < 8388608) { // 1-8M
quality = 0.9
} else if (size >= 8388608 && size < 16777216) { // 8-16M
quality = 0.8
} else {
quality = 0.5
}
// 压缩比例每减小0.1,约等于压缩8.5倍
await lrz(file, {
quality: quality // 自定义使用压缩方式
})
.then(function (rst) {
// 成功时执行
let _name = rst.origin.name
let _type = rst.origin.type
let _file = rst.file
file = new window.File([_file], _name, { type: _type })
formData.append('file', file)
}).catch(function (e) {
// 失败时执行
console.log(e)
}).always(function () {
// 不管成功或失败,都会执行
})
}
// 界面需展示文件大小,不需要展示可删除
size = (file.size / 1024).toFixed(2) + 'KB'
if (size === '0.00KB') {
// 使用的mint-ui
Toast('不支持传空文件')
return
}
// 上传的接口
await uploadFile(formData).then(res => {
if (res.data.success) {
// 页面需渲染的一些东西
id = res.data.data.fileId
url = res.data.data.url
}
}).catch(e => {
})
const windowURL = window.URL || window.webkitURL
let src
if (file.type.indexOf('image') !== -1) {
src = windowURL.createObjectURL(file)
} else if (file.type.indexOf('spreadsheetml.sheet') !== -1) { // excel表
src = require('../../assets/log/excl.png') // 需展示的图片
} else if (...) {
... // 其他类型
}
// 页面需渲染的数组
this.fileArr.push({ id: id, img: src, name: file.name, size: size, url: url })
}
},
【注】:
- 如果后端可以直接接收
blob
类型的文件,就不需要这行代码了:
new window.File([_file], _name, { type: _type })
因为这个插件是将用户选择的file
类型文件转为了blob
类型,接口接收的是file
类型,所以自己做了个转换。
-
lrz
压缩后不支持传空文件了,所以做了非空判断:
if (size === '0.00KB') {
// 使用的mint-ui
Toast('不支持传空文件')
return
}
- 需展示用户选择的图片的话:
const windowURL = window.URL || window.webkitURL
src = windowURL.createObjectURL(file) // src是img标签的属性
以上就是项目中前端压缩图片上传的所有功能,希望能帮到你。
总结
实际上,插件还有很多,但是lrz
在npm
上的weekly downloads
相对比较多,还是值得一用的。
有时间了在项目中尝试使用canvas
进行压缩。
脚本之家:JS和Canvas实现图片的预览压缩和上传功能
博客园:H5页面利用CANVAS压缩图片并上传
网友评论