前言

最近太忙一直没时间认真的写博客(哈哈哈),最近pm提一个需求,移动端需要一个上传图片的功能,允许多选、删除、预览、点击查看大图并可以滑动。虽然听起来很多,但是这个功能在web上实现过啊,使用webuploader妥妥的,然后就拍着胸口答应了下来,并让B同事做。

开发完成后,后端说同一次上传多张图只能发一次请求,纳尼。。我没仔细看过webuploader的API,不知道为什么需要单独进行上传,看了一下请求信息,在支持FormData的浏览器中使用的FormData来模拟form。那既然这样也可以支持多图一起请求啊(如果webuploader支持或者有其他考虑,欢迎大家指出),算了,自己造吧,也就有了这篇随笔。

1.form表单提交

像我这样的小白都知道form表单提交之后要刷新页面,更别说要实现pm提的那些需求了,但是代码还是要上一下的。

<form action="http://baidu.com" target="" id="uploadForm" enctype="multipart/form-data">
  <input id="file" type="file" name="file"/>
  <input type="submit" name="submit" id="submit" value="upload" />
</form>

因为我们这里要上传文件,所以enctype的值为multipart/form-data。

2.form+iframe

看到上面的代码,form有一个target的属性,规定在何处打开action,可能的值有

  • _blank
  • _self
  • _parent
  • _top
  • framename

就不一一介绍了,我们最关心的是最后一个值,framename,我们将页面放在iframe里处理就不担心刷新的问题了,然后再设置一个回调就可以处理服务端返回的参数

html:

<form action="http://baidu.com"  target="" id="uploadForm" enctype="multipart/form-data">
<input id="file" type="file" name="file"/>
<input type="submit" name="submit" id="submit" value="upload" />
</form>

jq:

<script type="text/javascript">
var form = $("#uploadForm");
form.on("submit",function(){
var seed = Math.floor(Math.random()*1000),
id = "uploader-iframe" + seed,
callback = "uploader-cb" + seed,
iframe = $("<iframe id='"+id+"' name='"+id+"' style='display:none'></iframe>"),
url = form.attr("action");
form.attr("target",id).append(iframe).attr("action",url+"?iframe="+callback);
window[callback]=function(data){
iframe.remove();
form.removeAttr("target");
form.attr("action",url);
window[callback] = undefined;
}
})
</script>

有没有觉得和jsonp的方式有点像,但是这里不需要动态创建script标签来调用,因为iframe本来就是一个页面,只需要服务端返回调用方法和数据在iframe页面就ok了

服务端返回:

<script type="text/javascript">
window.top.window[callback](data)
</script>

callback是我们事前约定好并传给服务器的参数,data为服务器返回的数据。

还有一种拿数据的方法,不通过后端回调

iframe.on("load",function(){
var ifr =$(this).contents() //jq对象document
//ifr = this.contentDocument || this.document//兼容ie
})

跟后端约定返回数据格式,然后进行操作

form+iframe这种伪异步的提交方式对文件的处理还是无力,不能想删就删,预览图片只有先传给后台,后台再返回一个线上的地址

3.HTML5之FormData、FileReader

当当当。。文章的主角出现

利用FormData模拟表单数据,通过ajax进行提交,FileReader的readAsDataURL方法拿到base64地址来预览(完美,注意兼容性)

form表单初始化FormData提交

<form action="http://baidu.com"  target="" id="uploadForm" enctype="multipart/form-data">
<input id="file" type="file" name="file"/>
<input type="submit" name="submit" id="submit" value="upload" />
</form>
$.ajax({
url: '/upload',
type: 'POST',
cache: false,
data: new FormData($('#uploadForm')[0]),
processData: false,
contentType: false
}).done(function(res) {
}).fail(function(res) {});
  • processData设置为false。因为data值是FormData对象,不需要对数据做处理。
  • <form>标签添加enctype="multipart/form-data"属性。
  • cache设置为false,上传文件不需要缓存。
  • contentType设置为false。因为是由<form>表单构造的FormData对象,且已经声明了属性enctype="multipart/form-data",所以这里设置为false。

上传后服务端通过file来接收文件流。

通过FormData对象append方法来添加

<div id="uploadForm">
<input id="file" type="file"/>
<button id="upload" type="button">upload</button>
</div>
var formData = new FormData();
formData.append('file', $('#file')[0].files[0]);
$.ajax({
url: '/upload',
type: 'POST',
cache: false,
data: formData,
processData: false,
contentType: false
}).done(function(res) {
}).fail(function(res) {});

FileReader获取DataUrl

<input multiple="multiple" id="file" type="file" name="file"/>
var reader = new FileReader();
reader.onload=function(e){
//e.target.result为$("#file")[0].files[0]的base64地址
}
reader.readAsDataURL($("#file")[0].files[0])

更多FormData和FileReader方法可以去查看一下API

4.flash实现

flash的实现不在我们讨论的范围,而且浏览器的支持对flash有很大的影响,现在有很多上传组件做了低版本flash的兼容。比如webuploader、uploadify等

需求实现

说了这么多,最后还是要回归到需求上来,由于这个需求是在移动端上,我们自然而然就选了第三种实现方式,这里讲一下实现的思路(伪代码)。

var formdata = new FormData(), count = 0, mId = '${model.id}', a = [];
formdata.append("id", mId)
$("#file").on("change",function() {//file触发change时循环files做相应的处理
if ($("#file")[0].files.length > 0) { for (var i = 0, j = $("#file")[0].files.length; i < j; i += 1) { (function(k) {//按顺序插入预览图片,并在数组中保存对应的files
var reader = new FileReader()
reader.onload = function(e) {//保证预览顺序和files数组顺序一致,方便后面删除file
count += 1;
a.push($("#file")[0].files[k]);
$(".filelist").append("<li><p class='imgWrap'><img class='close' src='img/close.png'/><img id='"
+ $("#file")[0].files[k].name
+ "' class='choose-img' src='"
+ e.target.result
+ "'' /></p></li>");//预览相关处理
$(".swiper-wrapper").append("<div class='swiper-slide'><img id='"
+ $("#file")[0].files[k].name
+ "' class='choose-img' src='"
+ e.target.result
+ "'' /></div>");//点击查看大图相关处理
} reader.readAsDataURL($("#file")[0].files[i]);
})(i); } }
});
$(document).on("click", ".close", function() {//图片删除处理,处理files数组,更新count
var $this = $(this);
a.splice($this.parents("li").index(), 1);
$(".swiper-slide").eq($this.parents("li").index()).remove();//如果考虑复用,这个index可以优化下
count -= 1;
$this.parents("li").remove();
$("#jsUpload").show();
})
$("#jsUploadBtn").on("click", function() {//上传时,将files数组循环append进FromData进行ajax提交
for (var i = 0, j = a.length; i < j; i += 1) {
formdata.append("file", a[i])
}
$.ajax({
url : '',
type : 'POST',
cache : false,
data : formdata,
processData : false,
contentType : false
}).done(function(data) {
if (data == 'error') {
$(".flie-toast").addClass("hide");
toast("上传失败,请联系管理员!");
} else if (data == 'no') {
$(".flie-toast").addClass("hide");
toast("您没有参与比赛,不允许上传截图");
} else if (data == 'yes') {
$(".flie-toast").addClass("hide");
toast("上传成功");
setTimeout(function() {
window.location.href = "";
}, 2000);
} else {
$(".flie-toast").addClass("hide");
toast("上传失败,请联系管理员!");
} }).fail(function(res) {
}); })

虽然FormData对象有一个delete的方法,但是现在浏览器的支持率堪忧啊,所以只有曲线救国了。

个人知识的宽度和广度毕竟有限,如文章有什么疏漏和错误的地方,欢迎大家留言指出。

web前端之文件上传的更多相关文章

  1. 基于 java 【Web安全】文件上传漏洞及目录遍历攻击

    前言:web安全之文件上传漏洞,顺带讲一下目录遍历攻击.本文基于 java 写了一个示例. 原理 在上网的过程中,我们经常会将一些如图片.压缩包之类的文件上传到远端服务器进行保存.文件上传攻击指的是恶 ...

  2. JAVA Web 之 struts2文件上传下载演示(二)(转)

    JAVA Web 之 struts2文件上传下载演示(二) 一.文件上传演示 详细查看本人的另一篇博客 http://titanseason.iteye.com/blog/1489397 二.文件下载 ...

  3. JAVA Web 之 struts2文件上传下载演示(一)(转)

    JAVA Web 之 struts2文件上传下载演示(一) 一.文件上传演示 1.需要的jar包 大多数的jar包都是struts里面的,大家把jar包直接复制到WebContent/WEB-INF/ ...

  4. FormData使用方法详解,以及在IE9环境下,前端的文件上传问题

    FormData的主要用途有两个: 1.将form表单元素的name与value进行组合,实现表单数据的序列化,从而减少表单元素的拼接,提高工作效率. 2.异步上传文件 一.创建formData对象 ...

  5. 构建web应用之——文件上传

    我们通过使用multipart请求数据接收和处理二进制信息(如文件).DispatcherServlet并没有实现任何解析multipart请求数据的功能,它将该任务委托给了Spring中的multi ...

  6. web实现大文件上传分片上传断点续传

    需求:项目要支持大文件上传功能,经过讨论,初步将文件上传大小控制在500M内,因此自己需要在项目中进行文件上传部分的调整和配置,自己将大小都以501M来进行限制. 第一步: 前端修改 由于项目使用的是 ...

  7. WEB安全性测试之文件上传漏洞

    1.漏洞描述:文件上传漏洞,是指可以利用WEB上传一些特定的文件包含特定代码如(<?php phpnfo;?> 可以用于读取服务器配置信息.上传成功后可以点击) 上传漏洞是指用户上传了一个 ...

  8. WEB安全:文件上传漏洞

    文件上传漏洞过程 用户上传了一个可执行的脚本文件,并通过此脚本文件获得了执行服务器端命令的能力. 一般的情况有: 上传文件WEB脚本语言,服务器的WEB容器解释并执行了用户上传的脚本,导致代码执行: ...

  9. IIS 之 通过 Web.config 修改文件上传大小限制设置方法

    在IIS 6.0中,不设置默认大小为4M,设置文件上传大小的方法,maxRequestLength(KB),executionTimeout(毫秒),配置如下节点: <system.web> ...

随机推荐

  1. css background-position:x% y%

    规则1: background-position:xpx ypx; 为正值时:背景图片的左上顶点朝右下移动直至距离div的左上顶点为xpx ypx: 规则2: background-position: ...

  2. phpcms v9联动菜单的调用方法_详解get_linkage函数

    phpcms v9联动菜单调用方法[此为内容页调用方法]: {get_linkage($areaid,1,' >> ',1)} 显示效果: phpcms吧 >> 模板下载 &g ...

  3. 在线支付接口之PHP支付宝接口开发简单介绍

    php100:92:在线支付接口之PHP支付宝接口开发 支付接口一般是第三方提供的代收款.付款的平台,可以通过支付接口帮助企业或个人利用一切可以使用的支付方式.常见支付平台:支付宝.快钱.云网支付.财 ...

  4. svn用法

    SVN安装与启动服务 1.下载相应匹配版本的TortoiseSVN(客户端)和Subversion(客户端),安装完毕之后. 2.配置相关文件. 选择TortoiseSVN-->create r ...

  5. JS之对象数组遍历?

    一.js实现遍历对象 <script> ","destroy":"97%"}; var props = ""; for ...

  6. jQueryMobile之Popup

    效果: (1):Tooltip (2):Menu (3):NestedMenu (4):Login ------ 源码: <!DOCTYPE html> <html lang=&qu ...

  7. webpy,希望能多了解一些关于WSGI,PYTHON的WEB开发框架的事,也希望能进一步了解PYTHON

    如果能真正看懂源代码,那就强了. 几年了,不应该总是小搞小打的. [Python]Webpy 源码学习(一) http://diaocow.iteye.com/blog/1922760 学习线路: 那 ...

  8. BZOJ 1211 树的计数

    http://www.lydsy.com/JudgeOnline/problem.php?id=1211 思路:每一个prufer编码都代表了一棵树,而点的度数,代表了它在prufer编码中出现的次数 ...

  9. day03_javaEE四成结构

  10. WebAPI 用户认证防篡改实现HMAC(二)签名验证 AbsBaseAuthenticationAttribute--转

    public class ActionFilter : ActionFilterAttribute      {          public override void OnActionExecu ...