最近主导的PC客户端网站重构工程告一段落,下一阶段开始给公司APP开发H5页面,技术栈是react。最近碰到一个需求:需要在H5页面上添加身份证照片,预览并上传。因为要兼容安卓4.4以下版本的手机,所以连html5的新属性formData都用不了,纯原生js实现。
首先获取input输入框,并给其注册onchange事件。
uploadImage(){ let idCardFrontParams={ showID: "img-box1", flag: "idCardFrontFileId" }; let $this=this; //获取页面的input标签 var idCardFrontFile = document.getElementById("idCardFrontFile"); idCardFrontFile.onchange = function () { let that = this; $this.preview(that, idCardFrontParams); }; }
接下来是实现上传并预览功能,预览的关键是使用getObjectURL方法来获得所上传图片的url地址。URL.createObjectURL()方法会根据传入的参数创建一个指向该参数对象的URL,这个URL的生命仅存在于它被创建的这个文档里,新的对象URL指向执行的File对象或者是Blob对象。其语法为:objectURL = window.URL.createObjectURL(blob || file);不同浏览器有差异
获得图片url后调用表单的方法submit将其上传, 并将其地址赋给指定的div。
preview(that, options) { //接受files数组列表 let _file = that.files,$this=this; if(_file[0]){ let addr = getObjectURL(_file[0]); let curFile=options.flag; this.setState({isLoading:true}); document.querySelector("#"+curFile).submit(); if(curFile==="deviceFileId"){ $this.setState({deviceFile:true}); }else if(curFile==="idCardFrontFileId"){ $this.setState({idCardFrontFile:true}); }else if(curFile==="idCardbackFileId"){ $this.setState({idCardBackFile:true}); } var fileUpIframe = document.getElementById("file_upload_iframe"); fileUpIframe.onload = fileUpIframe.onreadystatechange = function () { try { var data = JSON.parse(fileUpIframe.contentWindow.document.body.innerHTML); if (data.code) { $this.submitParams[curFile]=""; alert("上传图片失败,请刷新页面重试!"); } else { $this.submitParams[curFile]=data.fileId; } $this.setState({isLoading:false}); }catch (err){ console.warn(err); } } let dom =document.getElementById(options.showID); dom.style.backgroundImage = "url("+addr+")"; } function getObjectURL(file) { let url = null; if (window.createObjectURL != undefined) { // basic url = window.createObjectURL(file); } else if (window.URL != undefined) { // mozilla(firefox) url = window.URL.createObjectURL(file); } else if (window.webkitURL != undefined) { // webkit or chrome url = window.webkitURL.createObjectURL(file); } return url; } }
在这里由于采用的是最原始的表单提交,而submit方法提交后会跳转,又不像ajax可以采用回调函数获取返回值,故需要一个iframe来承载表单提交后的返回值,用target来指向承载返回值的iframe。
<form action="/eyeplus/api/upload" method="post" encType="multipart/form-data" id="idCardbackFileId" target="file_upload_iframe"> <input id="idCardBackFile" type="file" accept="image/*" multiple="multiple" name="file" className="uploadImg"/> <input type="text" className="ub-hidden-ele ub-token" readOnly="readOnly" name="token" value={this.submitParams.token}/> <input type="text" className="ub-hidden-ele ub-clientId" readOnly="readOnly" name="client_id" value={this.submitParams.client_id}/> <input type="text" className="ub-hidden-ele ub-deviceId" readOnly="readOnly" name="device_id" value={this.submitParams.device_id}/> <input type="text" className="ub-hidden-ele ub-type" readOnly="readOnly" name="type" value="201" /> </form>
<iframe style={{display: "none"}} id="file_upload_iframe" name="file_upload_iframe"></iframe>
在确认服务器得到正确上传后的,使用方法JSON.parse(fileUpIframe.contentWindow.document.body.innerHTML)来解析服务器返回值,并与其它所需要的参数组合在一起,就可以愉快的进行下一步操作了。