最近主导的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[]){
let addr = getObjectURL(_file[]);
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="" />
</form>
<iframe style={{display: "none"}} id="file_upload_iframe" name="file_upload_iframe"></iframe>

在确认服务器得到正确上传后的,使用方法JSON.parse(fileUpIframe.contentWindow.document.body.innerHTML)来解析服务器返回值,并与其它所需要的参数组合在一起,就可以愉快的进行下一步操作了。

-----------------------------------------------------补充于2018/06/29--------------------------------------------------------------

以上方法虽然能完成需求开发,但后续测试的时候发现了一个问题:IOS手机是没问题的,只是在安卓手机上,在返回的时候因iframe的存在,导致多级页面从而使得页面标题栏变化但是页面内容没变化,故点击返回的时候并不能准确的返回。不得不说这是个大坑,经反复实践,采用了下面这种方法顺利通过测试。

preview(that, options) {
//接受files数组列表
let _file = that.files, $this = this;
if (_file[]) {
let addr = getObjectURL(_file[]);
let curFile = options.flag;
this.setState({isLoading: true});
if (curFile === "deviceFileId") {
$this.setState({deviceFile: true});
} else if (curFile === "idCardFrontFileId") {
$this.setState({idCardFrontFile: true});
} else if (curFile === "idCardbackFileId") {
$this.setState({idCardBackFile: true});
}
let dom = document.getElementById(options.showID);
dom.style.backgroundImage = "url(" + addr + ")"; let frameId = 'uploadFrame'+ new Date().getTime();
let fileUpIframe = document.createElement("iframe");
fileUpIframe.id = fileUpIframe.name = frameId;
fileUpIframe.style.display = 'none';
document.body.appendChild(fileUpIframe);
//let 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($this.props.locale.ub_fail_upload);
} else {
$this.submitParams[curFile] = data.fileId;
}
$this.setState({isLoading: false});
document.body.removeChild(fileUpIframe);
} catch (err) {
console.warn(err);
}
};
let form = document.querySelector("#" + curFile);
form.target = frameId;
form.submit();
}

即先去掉HTML文档中存在的iframe,然后在预览上传时create一个iframe,在上传时修改表单提交的target为此新建iframe的ID,上传完成后获取到数据移除掉这个iframe,从而避免了单页面存在多级页面的问题。

原生js实现图片预览并上传的更多相关文章

  1. 基于“formData批量上传的多种实现” 的多图片预览、上传的多种实现

    前言 图片上传是web项目常见的需求,我基于之前的博客的代码(请戳:formData批量上传的多种实现)里的第三种方法实现多图片的预览.上传,并且支持三种方式添加图片到上传列表:选择图片.复制粘贴图片 ...

  2. 原生JS实现图片预览功能

    html代码: <div class="album-new fr"> <div class="upload-btn btn-new container& ...

  3. H5-FileReader实现图片预览&Ajax上传文件

    图片预览 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF- ...

  4. js多图预览及上传功能

    <%-- Created by IntelliJ IDEA. User: Old Zhang Date: 2018/12/27 Time: 11:17 To change this templa ...

  5. 前端图片预览,上传前预览,兼容IE7、8、9、10、11,Firefox,Chrome(学习到的知识)

    文章地址:http://www.cnblogs.com/rubylouvre/p/4597344.html 一.window.URL 在Chrome中,window.URL和window.webkit ...

  6. jquery+html5+canvas实现图片 预览 压缩 上传

    javascirpt (function($){ $.fn.extend({ aiiUpload:function(obj) { if(typeof obj !="object") ...

  7. vue组件利用formdata图片预览以及上传《转载》

    转载修改 在项目中直接新建一个单文件页,复制一下代码即可       upload组件: <template> <div class="vue-uploader" ...

  8. vue组件利用formdata图片预览以及上传

    转载修改 在项目中直接新建一个单文件页,复制一下代码即可       upload组件: <template> <div class="vue-uploader" ...

  9. 用js实现预览待上传的本地图片

    js实现预览待上传的本地图片,代码如下: <form name="form5" id="form5" method="post" ac ...

随机推荐

  1. 分析new delete 的本质

    在程序设计中,数据可能会存在不同的内存空间,如函数栈 堆   全局变量区  ,今天我们来分析一下C++中堆分配方式和C语言的堆分配方式异同,从而更好的理解new  delete本质 C语言使用mall ...

  2. JS、JQ实现焦点图轮播效果

    JS实现焦点图轮播效果 效果图: 代码如下,复制即可使用: (不过里面的图片路径需要自己改成自己的图片路径,否则是没有图片显示的哦) <!DOCTYPE html> <html> ...

  3. Python 安装 pytesser 处理验证码出现的问题

    今天这个问题困扰了我好久,开始直接用 pip install pytesseract 安装了 pytesseract 然后出现了如下错误 Traceback (most recent call las ...

  4. BFS && DFS

    HDOJ 1312 Red and Black http://acm.hdu.edu.cn/showproblem.php?pid=1312 很裸的dfs,在dfs里面写上ans++,能到几个点就调了 ...

  5. Spring+Dubbo集成Redis的两种解决方案

    当下我们的系统数据库压力都非常大,解决数据库的瓶颈问题势在必行,为了解决数据库的压力等需求,我们常用的是各种缓存,比如redis,本文就来简单讲解一下如何集成redis缓存存储,附github源码. ...

  6. day7 socket网络编程

    Python Socket网络编程 Socket是进程间通信的一种方式,它与其他进程间通信的一个主要不同是:它能实现不同主机间的进程间通信,我们网络上各种各样的服务大多都是基于Socket来完成通信的 ...

  7. 【社区公益】送《Web前端开发最佳实践》给需要的人

    算起来至今,我进入软件开发行业已经有11年之久.从最初的研究人工智能,到后来的Web开发,控件开发,直到现在纯粹的Web前端开发.虽然没有大的作品问世,但也是勤勤恳恳,踏实做事,低调做人.从来不吹牛逼 ...

  8. 《Android源码设计模式》--单例模式

    No1: 懒汉单例模式优缺点分析 public class Singleton{ private static Singleton instance; private Singleton(){} pu ...

  9. 哪来的gou zi 阿龙(最新更新于1.21日)

    众所周知,信息竞赛教室有一个特gou zi的人,叫做阿龙. 这个人呢,特别好玩,特别gou zi 还有一个人,叫Sugar,这个人特别喜欢和阿龙闹,so,一系列爆笑无脑的事就发生了! 1.谁是鱼? 一 ...

  10. 「长乐集训 2017 Day10」划分序列 (二分 dp)

    「长乐集训 2017 Day10」划分序列 题目描述 给定一个长度为 n nn 的序列 Ai A_iA​i​​,现在要求把这个序列分成恰好 K KK 段,(每一段是一个连续子序列,且每个元素恰好属于一 ...