由于业务需要,用户要通过移动端上传图片,并且前端要对上传图片进行压缩,然后再上传到服务器,这样可以 减少移动端上行流量,减少用户上传等待时长,优化用户体验
获取文件对象
-
普通函数
fileInputEl.addEventListener('change', function() { const files = [...this.files] }) -
箭头函数
fileInputEl.addEventListener('change', ({target}) => { const files = [...target.files] }) -
踩坑问题
选择文件后,文件名会存放在表单的
value值中,如果该值选取前后不发生变化,就不会触发change事件打开文件选择对话框,在未选取任何文件对象的情况下,点击取消关闭文件选择框时,会触发
change事件 -
解决方案
在获取到文件对象后,清空表单的
value值fileInputEl.addEventListener('change', ({target}) => { const files = [...target.files] target.value = null })
压缩文件对象
- 通过 file 对象获取 Image 对象
const getImage = file => { return new Promise((resolve, reject) => { const image = document.createElement('img') const temporaryUrl = URL.createObjectURL(file) Object.assign(image, { onload() { resolve(image) URL.revokeObjectURL(temporaryUrl) }, onerror: reject, src: temporaryUrl }) }) } - 将 Image 对象绘画在 Canvas 对象上
const paintingImageToCanvas = image => { const {naturalWidth, naturalHeight} = image const canvas = document.createElement('canvas') Object.assign(canvas, { width: naturalWidth, height: naturalHeight }) canvas.getContext('2d').drawImage(image, 0, 0, canvas.width, canvas.height) return canvas } - 通过 Canvas 对象压缩文件对象
通过调整const compressPicture = ([file], quality = 0.65) => { return new Promise(async resolve => { const image = await getImage(file) const canvas = paintingImageToCanvas(image) canvas.toBlob(blob => resolve(blob), 'image/jpeg', quality) }) }quality参数来指定压缩图片的展示质量,取值在0与1之间
等比例缩放压缩
-
缩放原理
通过等比例缩放可以有效避免压缩图片变形
输出目标高度 * 宽高比(aspectRatio)= 等比缩放后的宽若比输出目标宽度小,则以输出目标高度为基准缩放,否则以宽度为基准缩放
-
缩放计算
const uniformScale = ({naturalWidth, naturalHeight}, width, height) => { const aspectRatio = naturalWidth / naturalHeight // Image 对象原始尺寸宽高比 width = width || naturalWidth height = height || naturalHeight if (height * aspectRatio > width) { height = width / aspectRatio } else { width = height * aspectRatio } return { width, height } } -
应用压缩
在 getImage 方法中给 Image 对象设置等比宽高Object.assign(image, { onload() { const targetSize = uniformScale(this, width, height) Object.assign(this, targetSize) resolve(image) URL.revokeObjectURL(temporaryUrl) } })在 paintingImageToCanvas 方法中读取 Image 对象的宽高设置给 Canvas 对象const paintingImageToCanvas = (image) => { const canvas = document.createElement('canvas') Object.assign(canvas, { width: image.width, height: image.height }) canvas.getContext('2d').drawImage(image, 0, 0, canvas.width, canvas.height) return canvas }一起学习,加群交流看 沸点