这几年,前端技术日新月异,浏览器/h5获得的权限越来越多。这里使用h5页面做一个相册的上传功能,读取手机相册、上传到服务器,要求能够一次选择多张、上传前能看到预览、并能显示各个照片的上传进度。看到这里,有朋友肯定说:这有何难,input-file标签早就已经有multiple属性,加了它就能选多图了。呵呵,看起来简单,实际做起来问题还挺多。这里按顺序列一几个卡主的地方和解决方法:
1. 多图上传
看到这里,肯定有人说了,不是有multiple属性吗?
确实有,可实际用起来,不一样的
iphone好办,全都支持一次选择多张图片
Android手机有点麻烦,部分手机、部分浏览器不支持一次选多图;而且即便支持选多图,交互方式也不一样。比如我手头这台华为/荣耀,微信内置浏览器只能一次选一张图,改用系统浏览器,虽然可以选多张,但是需要长按,对于不熟悉的用户,可能发现不了这个功能,这就需要在应用里加指引;旁边同事的锤子就还好,微信内置浏览器就能选多图,和iphone的体验类似
2. 上传前的预览
这个功能说白了,就是怎么拿到本机图片文件、放到img标签的src里。前端浏览器的权限限制一直很严格,对于图片上传当然也是如此,肯定不会把文件路径给你。试了几个方案,最终用的是FileReader读取、转base64显示。第一次用前端的FileReader功能,还算好用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | var imgB64Arr = []; //fileInput是input标签 fileInput.change=function(){ var files = this.files; for(var j = 0; j < files.length; j++){ var reader = new FileReader(); reader.readAsDataURL(files[j]); reader.onload = function(){ var v64 = this.result; imgB64Arr.push(b64); //...预览显示逻辑... }; } }; |
这个方案将图片的base64编码放在了imgB64Arr数组里,以方便后续上传处理。不过考虑到现代手机拍照的大小,和多选功能,如果一次选的图很多,会占用大量的内存,所以这里流畅度待验证,可能需要优化
3. 逐个上传
分开上传的目的有二:
1). 递归上传,降低有网络问题带来的上传失败的概率
2). 分开显示上传进度,这样前端体验会更好
这里我偷了个懒,没用递归,而是定时轮训imgB64Arr数组,有内容就上传,上传完删掉,呵呵
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | var uploadingImg = false; //标示当前是否有正在上传的东西 setInterval(function(){ if(!uploadingImg && imgB64Arr.length > 0){ var nowUp = imgB64Arr[0]; uploadingImg = true; var imgName = 'xxx';//文件命名策略 subimtInageFile(imgName, imgBa64s[nowUp.img], function(retu, err){ if(err){ //TODO: 错误处理 return; } //上传完成相关数据维护 imgB64Arr = imgB64Arr.length > 0 ? imgB64Arr.slice(1) : []; uploadingImg = false; //TODO: 显示更新逻辑 }); } }, 300); function subimtInageFile(imgName, ba64, callback){ var formData = new FormData(); formData.append('up_photo', convertBase64UrlToBlon(ba64)); //这里服务端要留意:没找到怎么把名字写到上传文件里,所以将文件名直接作为单独一个post参数提交 formData.append('file_name', imgName); $.ajax({ url: '...', type: 'POST', data: formData, dataType: 'json', processData: false, //否则jquery会报错 contentType: false, success: function(sd){ callback && callback(sd); }, error: function(xhr, err){ callback && callback(false, err); } }); } //图片处理,base64欢迎成图片blob function convertBase64UrlToBlon(base64Str){ var bs = window.atob(base64Str.split(',')[1]); var ab = new ArrayBuffer(bs.length); var ia = new Uint8Array(ab); for(var i = 0; i < bs.length; i++) ia[i] = bs.charCodeAt(i); var bb = new Blob([ab], {type: 'image/png'}); return bb; } |
———-
写到这里,大概有朋友要说了:这么麻烦干嘛,微信有wx.chooseImage()不香吗?没错,要是能调微信api的需求,当然就不用上面这么麻烦了O(∩_∩)O~
over
转载请注明出处:http://www.jiangkl.com/2022/01/h5_file_multiple