页面里经常要用到文件上传的功能,而且要求页面不刷新,先说一下原理:页面里放一个file控件和submit按钮,外面用form表单包住,给form表单加上对应的属性值,action、method、entype、name,到这一步,能上传文件了,但是这样上传文件会刷新页面,这不是我们想要的。我们要的是文件上传时不刷新页面,那么也简单,在页面里放一个iframe,设置它的宽高为0,这里有两个坑:

1、需要设置iframe的name值与form的target属性值一样,意思就是把form表单上传文件的刷新转嫁到iframe里去了;

2、form表单的enctype属性值必须设置成multipart/form-data,将文件转换成文件流供后端接收;

代码如下:

<iframe name="fileUpload"></iframe>
<form method="post" action="xxxx" enctype="multipart/form-data" name="fileForm" target="fileUpload">
<input type="file" class="fileInput" name="fileInput">
<input type="submit" value="提交" />
</form>

页面(这里为了看到效果,就不将iframe的宽高设为0了):

事情就这么愉快地结束了吗?当然没有,离国庆节还有那么些天,不要着急。

到这里文件能上传了,页面也不会刷新,那么还差什么?当然是精益求精--优化啦。怎么优化?假如页面里有三个地方需要上传不同类型的文件,最好的办法肯定不是在页面里将代码copy三份,然后就这样用,这是普通开发的做法,我们可以利用js动态生成上面这些代码,需要上传文件的地方,一个函数加参数就搞定了,代码如下:

/*2014年9月18日17:39:47 By 王美建*/
function ajaxUpload(opt){
/*
参数说明:
opt.frameName : iframe的name值;
opt.url : 文件要提交到的地址;
opt.fileName : file控件的name;
opt.format : 文件格式,以数组的形式传递,如['jpg','png','gif','bmp'];
opt.callBack : 上传成功后回调;
*/
var iName=opt.frameName; //太长了,变短点
var iframe,form;
//创建iframe和form表单
iframe = $('<iframe name="'+iName+'" />');
form = $('<form method="post" style="display:none;" target="'+iName+'" action="'+opt.url+'" name="form_'+iName+'" enctype="multipart/form-data" />');
file = $('<input type="file" name="'+opt.fileName+'" />');
file.appendTo(form);
//插入body
$(document.body).append(iframe).append(form);
//触发浏览事件,选择文件
file.click();
//选中文件后,验证文件格式是否符合要求
file.change(function(){
//取得所选文件的扩展名
var fileFormat=$(this).val().exec(/\.[a-zA-Z]+$/)[0].substring(1);
if(opt.format.join('-').indexOf(fileVal)!=-1){
form.submit();//格式通过验证后提交表单;
}else{
iframe.remove();
form.remove();
alert('文件格式错误,请重新选择!');
}
});
//文件提交完后
iframe.load(function(){
var data = $(this).contents().find('body').html();
opt.callBack(data);
iframe.remove();
form.remove();
})
}
使用方法:在页面里放一个按钮Btn,点击Btn时触发ajaxUpload方法,ajaxUpload方法内部自动创建上传所需要的元素并自动触发file.click()事件供用户选择文件,选中文件后自动验证文件格式并提交,然后返回后端返回的结果,到这里,问题解决了80%,为什么不是100%?ajaxUpload方法在IE8以上及火狐、chrome浏览器都没有问题,但在IE8及以下的浏览器上传文件会提示:没有权限!这是因为低版本的IE做了安全限制,file控件必须由用户主动点击触发选择的文件才可以上传,而不能使用js的click事件来模拟点击触发。在此我又想说,IE我~!@#¥%……&*()——……。
办法总比困难多,既然一定要由用户点击来触发,那么直接把页面里的按钮替换成file控件吧,iframe和form还是动态创建,当用户点击file控件选择文件后,会触发file控件的chang事件,给file控件的change事件绑定ajaxUpload方法并将file控件的id传进去,ajaxUpload方法通过id获取file控件并将file控件appendTo到动态创建的form里,之后的步骤与上面无异——验证格式→提交表单→触发回调。细心的同学会发现,选择文件后,file控件会appendTo到form表单里,那页面里放file控件的地方不是空了么?并且,表单提交后,file会随着form一起被remove掉,所以,在file控件appendTo到form前,先建一个变量P将file控件的父级存起来,form表单提交之后,先将file控件appendTo回到P里面,当然,file控件appendTo到form时,file控件依然会在页面里消失,所以页面里的Btn要保留,把file控件定位在Btn上面,透明度设置成0,这样点击Btn实际上点击的是盖在上面的file控件,这样即使file控件被appendTo到form里面,用户也不会察觉到什么变化,问题迎刃而解!兼容的写法如下:
/*2014年9月19日11:11:07 By 王美建*/
function ajaxUpload(opt){
/*
参数说明:
opt.id : 页面里file控件的ID;
opt.frameName : iframe的name值;
opt.url : 文件要提交到的地址;
opt.format : 文件格式,以数组的形式传递,如['jpg','png','gif','bmp'];
opt.callBack : 上传成功后回调;
*/
var iName=opt.frameName; //太长了,变短点
var iframe,form,file,fileParent;
//创建iframe和form表单
iframe = $('<iframe name="'+iName+'" />');
form = $('<form method="post" style="display:n1one;" target="'+iName+'" action="'+opt.url+'" name="form_'+iName+'" enctype="multipart/form-data" />');
file = $('#'+opt.id); //通过id获取flie控件
fileParent = file.parent(); //存父级
file.appendTo(form);
//插入body
$(document.body).append(iframe).append(form); //取得所选文件的扩展名
var fileFormat=/\.[a-zA-Z]+$/.exec(file.val())[0].substring(1);
if(opt.format.join('-').indexOf(fileFormat)!=-1){
form.submit();//格式通过验证后提交表单;
}else{
file.appendTo(fileParent); //将file控件放回到页面
iframe.remove();
form.remove();
alert('文件格式错误,请重新选择!');
}; //文件提交完后
iframe.load(function(){
var data = $(this).contents().find('body').html();
file.appendTo(fileParent);
iframe.remove();
form.remove();
opt.callBack(data);
})
}
国际惯例,到这里,方法已经接近完美了,为什么是接近?来看一张图片:

结构代码:
.fileInput{ position: absolute;left: 0;top: 0;height: 30px; filter:alpha(opacity=60);opacity:0.6; background-color: transparent;}
.btn{width: 200px;height: 30px; margin: 100px auto; background-color: yellow; text-align: center; line-height: 30px; overflow: hidden; display: block; position: relative;}
<div class="btn">选择文件<input type="file" class="fileInput" name="fileInput"></div>
这就是放在页面里的file控件,外面用一个div包住,在IE10及以下浏览器中,用户单击红色框部分是不会弹出文件选择框的,必须单击蓝色部分或双击红色部分才行,要让蓝色部分占满外面的div怎么做到呢?用css设置宽度只会增加红色部分的宽度,这时我们会发现蓝色部分是有字的,对,可以通过设置font-size来使蓝色部分变宽,然后给file控件加上dir="rtl",这会让浏览按钮移到左边,再给.btn加上overflow:hidden,可以发现浏览按钮已经占满整个div了,如下图:

到这里才真正完成了100%,最后,我们还可以给file控件设置accept属性,限制可选文件格式(IE8及以下不支持该属性),别忘了把file控件的透明的改为0。

利用iframe无刷新上传文件的坑的更多相关文章

  1. ajax +jsp+iframe无刷新上传文件[转]

    http://hi.baidu.com/zj360202/blog/item/f23e3711f929c774cb80c475.html ajax jsp 无刷新上传文件 2009-10-26 16: ...

  2. Html使用Iframe无刷新上传文件,后台接收

    html代码:我是发送请求到teacher_center.aspx,不是到.ashx一般处理程序里,需要加 runat="server",有空我再试试发送请求到 .ashx 里 & ...

  3. web 开发之js---巧用iframe实现jsp无刷新上传文件

    首先要说的就是 ajax 是无法实现上传文件的,可以想一下ajax与后台通信都是通过传递字符串,怎么能传递文件呢?其实出于安全考虑js是不能操作文件的,所以就不要再说用ajax来实现文件的上传了,这是 ...

  4. $_FILES参数详解及简单<form>表单无刷新上传文件

    $_FILES:经由 HTTP POST 文件上传而提交至脚本的变量,类似于旧数组$HTTP_POST_FILES 数组(依然有效,但反对使用)详细信息可参阅 POST方法上传 $_FILES数组内容 ...

  5. jquery ajax php 无刷新上传文件 带 遮罩 进度条 效果的哟

    在很多项目中都会叫用户上传东西这些的,自从接触了jquery 和ajax之后就不管做什么,首先都会想到这个,我这个人呢?是比较重视客户体验的,这次我这边负责的是后台板块,然后就有一块是要求用户上传照片 ...

  6. jQuery+php+ajax实现无刷新上传文件功能

    jQuery+php+ajax实现无刷新上传文件功能,还带有上传进度条动画效果,支持图片.视频等大文件上传. js代码 <script type='text/javascript' src='j ...

  7. Ajax 无刷新上传文件插件 uploadify 的使用

    在表单中无法直接使用 Ajax 上传文件,解决的思路可以是使用插件无刷新地上传文件,返回文件上传后的地址,然后把该地址作为 Ajax 的参数传递给服务器端进行数据库处理.可以使用 uploadify ...

  8. ajax无刷新上传文件

    网页上传文件最简单的方式就是通过表单上传了,但是在提交表单的时候会导致网页刷新,但有的时候我们不想网页刷新,有什么办法呢,我们可以使用ajax上传文件来做到这一点.只有ajax还不行,还需要JavaS ...

  9. .net MVC借助Iframe实现无刷新上传文件

    html: <div id="uploadwindow" style="display: none;"> <form action=" ...

随机推荐

  1. filter and listener

    Java Servlet 是运行在 Web 服务器或应用服务器上的程序,它是作为来自 Web 浏览器或其他 HTTP 客户端的请求和 HTTP 服务器上的数据库或应用程序之间的中间层. 使用 Serv ...

  2. (C#)算法题

    1. Convert string from "AAABBCC" to "A3B2C2". 当面试者提出这个问题的时候,首先需要确认题意:譬如:字符串是不是顺序 ...

  3. MyBatis无法根据中文条件查询出结果

    情况是这样的 , 以英文做参数可以查询到结果 , 以中文做参数则查询不到结果 在mysql workbench中执行sql , 可以查询到结果. 这是mybatis中没有指定utf-8的缘故导致的. ...

  4. Python-Tkinter几何布局管理(转)

    所有的Tkinter组件都包含专用的几何管理方法,这些方法是用来组织和管理整个父配件区中子配件的布局的.Tkinter提供了截然不同的三种几何管理类:pack.grid和place. pack() p ...

  5. switch语句

    应用条件语句可以很方便地使程序实现分支,但是出现分支比较多的时候,虽然可以用嵌套的if语句来解决,但是程序结构会显得复杂,甚至凌乱.为方便实现多情况选择,C++提供了一种switch开关语句.   一 ...

  6. 9. Sort List && Insertion Sort List (链表排序总结)

    Sort List Sort a linked list in O(n log n) time using constant space complexity.                   H ...

  7. Android:去掉默认的标题bar

    要使用自己定义的bar,只需要在layout文件中添加:<include layout="@layout/actionbar" />;当然你需要新建一个actionba ...

  8. ImageMagick之PDF转换成图片(image)

    安装完ImageMagick之后,直接执行“magick convert f:\parseWord\tmp\testpdf.pdf f:\parseWord\tmp\testpdf.jpg”,会报错: ...

  9. SQL Server添加MDW性能监控报表(转载)

    10.2 Data Collector与MDW Data Collection功能是SQL SERVER 2005版本提供的数据库监控报表的功能,通过定时地对数据库的语句运行情况,服务器各种资源的监控 ...

  10. 【EF学习笔记05】----------操作内存中的数据

    SingleOrDefault实验 //SingleOrDefault实验 using (var db = new Entities()) { var classes = new Classes() ...