咱们一般在作图片上传的时候都会赶上这样的状况,一是后端接口限制上传图片的大小,或者是即便后端没有限制大小,由于图片太大在前端渲染时太慢,形成页面加载体验较差。所以咱们颇有必要对上传的图片进行压缩。前端
本文在gitthub作了收录:github.com/Michael-lzg…vue
本文主要包括如下流程:webpack
input
框选择图片FileReader
进行图片预览canvas
画布上canvas
画布的能力进行图片压缩Base64(DataURL)
格式的数据转换成 Blob
对象进行上传经过设置 input
标签的 type
属性为 file
,来让用户能够选择文件,设置 accept
限制选择的文件类型,绑定 onchange
事件,来获取确认选择后的文件git
<input type="file" accept="image/*" onchange="loadFile(event)"
FileReader
是什么,咱们先来看看官方文档的介绍github
FileReader 对象容许 Web 应用程序异步读取存储在用户计算机上的文件(或原始数据缓冲区)的内容,使用 File 或 Blob 对象指定要读取的文件或数据。
FileReader
经常使用的两个方法以下:web
FileReader.onload
:处理 load
事件。即该钩子在读取操做完成时触发,经过该钩子函数能够完成例如读取完图片后进行预览的操做,或读取完图片后对图片内容进行二次处理等操做。FileReader.readAsDataURL
:读取方法,而且读取完成后,result
属性将返回 Data URL
格式(Base64 编码)的字符串,表明图片内容。在图片上传中,咱们能够经过 readAsDataURL()
方法进行了文件的读取,而且经过 result
属性拿到了图片的 Base64(DataURL)
格式的数据,而后经过该数据实现了图片预览的功能vue-cli
<div class="container"> <input type="file" accept="image/*" onchange="loadFile(event)" /> </div> <script> const loadFile = function (event) { let file = event.target.files[0] const reader = new FileReader() reader.onload = function () { console.log(reader.result) ... } reader.readAsDataURL(file) } </script>
这是图片上传压缩的核心所在,咱们先使用 CanvasRenderingContext2D.drawImage()
方法将上传的图片文件在画布上绘制出来,再使用 Canvas.toDataURL()
将画布上的图片信息转换成 base64(DataURL)
格式的数据。npm
drawImage()
方法在画布上绘制图像、画布或视频。drawImage()
方法也可以绘制图像的某些部分,以及/或者增长或减小图像的尺寸。参数以下canvas
var cas = document.querySelector('canvas') var ctx = cas.getContext('2d') // 先建立图片对象 var img = new Image() img.src = './images/1.jpg' // 图片加载完以后 img.onload = function () { ctx.drawImage(img, 206, 111, 32, 38, 100, 100, 32, 38) }
Canvas.toDataURl()
方法能够将 canvas
画布上的信息转换为 base64(DataURL)
格式的图像信息,纯字符的图片表示形式。该方法接收 2 个参数:后端
mimeType
(可选): 表示须要转换的图像的 mimeType
类型。默认值是 image/png
,还能够是 image/jpeg
, image/webp
等。quailty
(可选):quality 表示转换的图片质量。范围是 0 到 1。图片的 mimeType
须要是 image/jpeg
或者 image/webp
,其余 mimeType
值无效。默认压缩质量是 0.92。var canvas = document.createElement('canvas') canvas.toDataURL("image/jpeg" 0.8)
到这里,咱们先来上 canvas 压缩图片的代码
function compress(base64, quality, mimeType) { let canvas = document.createElement('canvas') let img = document.createElement('img') img.crossOrigin = 'anonymous' return new Promise((resolve, reject) => { img.src = base64 img.onload = () => { let targetWidth, targetHeight if (img.width > MAX_WIDTH) { targetWidth = MAX_WIDTH targetHeight = (img.height * MAX_WIDTH) / img.width } else { targetWidth = img.width targetHeight = img.height } canvas.width = targetWidth canvas.height = targetHeight let ctx = canvas.getContext('2d') ctx.clearRect(0, 0, targetWidth, targetHeight) // 清除画布 ctx.drawImage(img, 0, 0, canvas.width, canvas.height) let imageData = canvas.toDataURL(mimeType, quality / 100) resolve(imageData) } }) }
window.atob
将 base-64
字符串解码为 binaryString
(二进制文本);binaryString
构造为 multipart/form-data
格式;Uint8Array
将 multipart
格式的二进制文本转换为 ArrayBuffer
。function dataUrlToBlob(base64, mimeType) { let bytes = window.atob(base64.split(',')[1]) let ab = new ArrayBuffer(bytes.length) let ia = new Uint8Array(ab) for (let i = 0; i < bytes.length; i++) { ia[i] = bytes.charCodeAt(i) } return new Blob([ab], { type: mimeType }) }
FormData
,把 blob
append 到 FormData
里面function uploadFile(url, blob) { let formData = new FormData() let request = new XMLHttpRequest() formData.append('image', blob) request.open('POST', url, true) request.send(formData) }
ps:在实际开发中,咱们要不要把图片转化为 FormData
形式上传到服务端,这就看具体的业务须要了。咱们能够上图片上传到腾讯云,直接返回一个'https.xxx.jgp'
的图片 url 用于上传。
搭建一个 vue-cli4+webpack 移动端框架(开箱即用)
从零构建到优化一个相似vue-cli的脚手架
封装一个toast和dialog组件并发布到npm
从零开始构建一个webpack项目
总结几个webpack打包优化的方法
总结vue知识体系之高级应用篇
总结vue知识体系之实用技巧
总结vue知识体系之基础入门篇
总结移动端H5开发经常使用技巧(干货满满哦!)
关注的个人公众号不按期分享前端知识,与您一块儿进步!