业务有个需求,要做图片预览上传,过去都是客户端上传给后端,后端返回url前端进行预览,现在其实可以不依赖后端做预览,最后在上传,这主要依赖FileReader和FormData这两个对象和JavaScript处理二进制的能力。
OK,Show code~,以下代码已注释掉具体业务逻辑和实现,如果需要了解 API 细节,可以请参考:
https://developer.mozilla.org/en-US/docs/Web/API/FileReader
https://developer.mozilla.org/en-US/docs/Web/API/FormData/FormData
https://developer.mozilla.org/en-US/docs/Web/API/Blob/Blob
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer
文件表单的样式主要通过让它后面,通过别的DOM来美化它。
input.on.('change', preview);
预览使用FileReader对象来读:
functionpreview(e){varfile = e.target.files[0];varreader =newFileReader(); reader.onloadend =function(){// 图片的 base64 格式, 可以直接当成 img 的 src 属性值vardataURL = reader.result;varimg =newImage(); img.src = dataURL;// 插入到 DOM 中预览// ...}; reader.readAsDataURL(file);// 读出 base64}
base64 转 二进制文件
/*** dataURL to blob, ref to https://gist.github.com/fupslot/5015897 *@paramdataURI *@returns{Blob} */function dataURItoBlob(dataURI) { var byteString = atob(dataURI.split(',')[1]); var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0]; var ab =newArrayBuffer(byteString.length); var ia =newUint8Array(ab);for(var i =0; i < byteString.length; i++) { ia[i] = byteString.charCodeAt(i); }returnnewBlob([ab], {type: mimeString});}
构造FormData填充二进制文件数据,通过ajax的方式进行提交:
varfd =newFormData();varblob = dataURItoBlob(dataURL);fd.append('file', blob);$.ajax({ type:'POST', url:'/upload', data: fd, processData:false,// 不会将 data 参数序列化字符串contentType:false,// 根据表单 input 提交的数据使用其默认的 contentTypexhr:function() {varxhr =newwindow.XMLHttpRequest(); xhr.upload.addEventListener("progress",function(evt) {if(evt.lengthComputable) {varpercentComplete = evt.loaded / evt.total; console.log('进度', percentComplete); } },false);returnxhr; }}).success(function(res){// 拿到提交的结果}).error(function(err){console.error(err);});
注意:不要漏了指定processData和contentType为false。
业务中不需要前端不需要压缩,因为后端有更靠谱的压缩方案,但是前端其实也可以压缩,那就是用canvas把图画出适合的大小,然后上传。
在new出来的Image对象,我们监听它的onload事件
按照压缩比例,算出压缩后的图片尺寸
创建canvas,尺寸设置成上一步骤算出来的压缩后的图片尺寸
调用drawImage方法,把图片绘制到canvas中
调用canvas的toDataURL,取出base64格式的数据
后续的传图步骤和上面的原图上传一样
varimg =newImage();img.onload =function(){// 当图片宽度超过 400px 时, 就压缩成 400px, 高度按比例计算// 压缩质量可以根据实际情况调整varw = Math.min(400, img.width);varh = img.height * (w / img.width);varcanvas = document.createElement('canvas');varctx = canvas.getContext('2d');// 设置 canvas 的宽度和高度canvas.width = w; canvas.height = h;// 把图片绘制到 canvas 中ctx.drawImage(img,0,0, w, h);// 取出 base64 格式数据vardataURL = canvas.toDataURL('image/png');// ...};img.src = reader.result;
自己的OneWord客户端的上传组件就是这么做的:ow-image-uploader.vue
PS:需要注意的是,通过canvas绘制的图片,低版本iOS会出现比例不正确的情况,请参考https://github.com/stomita/ios-imagefile-megapixel
原地址:http://blog.csdn.net/huanghongfei1/article/details/61216852