自从web进入了2.0的时代,文件上传的功能几乎是遍地开花。小到设置头像,大到网盘管理,都离不开文件上传的功能。今天小剧就来扒一扒和文件上传相关的事儿(本文不讨论swf的上传方式)。
裸奔时代
这里提到的是最原始,也是最基础的上传方式,form提交。只需指定method
、action
、enctype
,再配合一个文件域(input
,type=“file”
)即可完成上传。
<form method="post" action="/ajax/upload" enctype="multipart/form-data>
<input name="file" type="file">
<input type="submit">
</form>
显而易见,这种上传方式是需要将文件提交到另一个接收上传的页面里。对的,你没有听错,是接收上传的页面,而不是上传接口。所有的接下来的流程必须在接收上传的页面上完成(或者有更精妙的处理方式,这里暂不讨论)。文件上传对于流程的打断其实是蛮严重的。
石器时代
聪明能干的前端工程师们为了解决页面跳转问题,找到了一个较为人性化的方式。因为form提交有一个属性,叫target
。可用的属性值和a
标签一样,也可以接受自定义名称。利用这个属性,即可完成form表单向特定的页面或iframe进行提交。通过监听iframe的返回值来判断上传结果,而不影响当前页面流程。
<iframe id="uploadA" name="uploadA" src="about:blank"></iframe>
<form method="post" action="/ajax/upload" enctype="multipart/form-data" target="uploadA">
<input name="file" type="file">
<input type="submit">
</form>
青铜器时代
上传问题解决,这时候对美的追求也开始了。就像大伙儿知道的一样,文件域在各个浏览器下的外观其实是千差万别的。于是乎在上一时代的基础上,开始了艺术创作。既然需要统一上传按钮的外观,文件域又很难驯服,那就只能狠心的让文件域隐藏不可见,但又可以被用户点击。
<div class="uploadBtn">
<span>上传</span>
<iframe id="uploadA" name="uploadA" src="about:blank"></iframe>
<form method="post" action="/ajax/upload" enctype="multipart/form-data" target="uploadA">
<input name="file" type="file" />
</form>
</div>
.uploadBtn{
position: relative;
100px;
height: 26px;
text-align: center;
line-height: 26px;
background: #f70;
overflow: hidden;
}
.uploadBtn span{
color: #fff;
}
.uploadBtn input{
position: absolute;
top: 0;
right: 0;
200%;
height: 100%;
}
#uploadA{
position: absolute;
left: -10px;
display: block;
0;
height: 0;
border- 0;
}
var iframe = $('#uploadA')[0];
//文件变动,自动上传
$('.uploadBtn input').on('change',function(){
$(this).parents('form').submit();
});
//监听iframe onload事件
if (iframe.attachEvent){
iframe.attachEvent("onload", function(){
//iframe.contentDocument
});
}else{
iframe.onload = function(){
//iframe.contentDocument
};
}
通过这样一番改造,在css
与javascript
的精心配合下,用户完全看不见了文件域的踪影,却又在不知不觉中使用着,由最传统的上传方式改造后的功能。
这里简单提下文件域的处理
外观就不说了,直接上交互。IE下,点击浏览按钮即可弹出系统文件选择器,而左侧大部分的区域需要双击才能生效,chrome下则是点击文件域下任意区域即可,firefox部分版本点击左侧无效。
既然左侧区域这么不靠谱,直接用右侧作为点击区域好了,这就是上面的css使用靠右定位input的原因。
这样子就足够了么?显然不。因为小剧前期参与的产品中,上传按钮区域较小,问题并未暴露出来,这里说下问题。
还是IE,因为IE右侧的按钮宽度其实是个相对固定的大小,当上传按钮(给用户看的)宽度大于input的浏览按钮后,同样会出现双击才能选择文件的bug(我说我用过mousemove来解决这个问题你会信我)。
火炮时代
以上的解决是大多数web非插件的上传方式。经过小剧实践,又找到一种较为猥琐的触发方式。
相信很多小伙伴都用过jQuery的trigger方法,用来主动触发一些事件还是很方便的。但是浏览器出于对用户的保护,很多高级事件是不会被响应的。比如移动端对输入框主动触发focus不会弹起软键盘,对文件域主动触发click不会弹出文件选择,等等。
偶然的一次手贱,被我发现,只要是用户主动click页面任何一个位置,与此同时(必须在原生事件的回调中),主动触发文件域的click,是可以调起系统的文件选择器的。
有了这一里应外合的同伙,上面费尽心机去勾搭鼠标、冒充按钮的事情都不用去做了。
PS:目前的上传插件多数为swf,少部分为swf与html5配合使用。本文仅作为抛砖引玉,让小伙伴们了解下原生上传需要注意的几个关键点。