重写File控件样式,实现文件异步上传

目前比较流行的Web端文件上传插件大多使用了Flash或HTML5技术,比如WebUploader。一个比较极端的情况是同时不具备以上环境,比如没有装Flash插件的IE8,基本上只剩下javascript模拟表单这一条路了。以下介绍一种比较简单的,利用CSS重写原生input(type=”file”)控件样式,实现文件异步上传的方法。

1 重写原生File控件的CSS样式

这里参考了input(file)浏览按钮美化提供的方法。

需要注意的是:IE9以下不支持opacity(透明度)属性,需要单独设置filter:alpha(opacity=0);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
input[type=file]
{
position: absolute;
right: 0;
top: 0;
font-size: 100px;
opacity: 0;
filter:alpha(opacity=0);
cursor: pointer;
}
#file-submit
{
display:none;
}

2 利用JQuery异步提交表单

用a标签代替原生input type="file"标签,利用JQuery在选择文件后将文件名显示在自定义文本框,点击自定义按钮时触发异步表单提交,上传完成后处理回调函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<!--注意:需要引用JQuery、JQuery Form-->
<script language="javascript" type="text/javascript">
$(document).ready(function () {
// 当选择文件时,将文件名显示在自定义文本框
$("#file-input").on("change", function () {
var filepath = $("#file-input").val();
$("#image-input").val(filepath.substr(filepath.lastIndexOf('\\') + 1));
$("#image-input").removeAttr("data-filename");
});

// 点击自定义保存按钮,上传文件
$("#save-btn").on("click", function () {
if ($("#file-input").val() == "") return;
var options = {
success: uploadPostback // post-submit callback
};
// 上传图片
$("#form_upload").ajaxSubmit(options);
});

// 上传完成后的回调函数
function uploadPostback(data) {
if (data.indexOf("error\\") != -1) {
$.alert(data.substring(6, data.length));
return;
}
// 保存实际文件名
$("#image-input").attr("data-filename", data);
}
});
</script>

<div class="input-group input-group-sm">
<span class="input-group-addon">Image</span>
<input type="text" class="form-control" id="image-input" readonly="readonly"/>
</div>
<form id="form_upload" action="UploadImage" method="post" enctype="multipart/form-data">
<a class="file-container btn btn-default pull-right">
获取<input type="file" name="upImg" id="file-input"/>
</a>
<input type="submit" value="上传" id="file-submit"/>
</form>

可能有人会问:为什么这么麻烦呢?直接将file控件hidden,再写一个button,点击时触发file控件的点击事件不行吗?实际上,file控件在IE下需要由用户手动触发事件选择文件,否则在表单提交的时候会报JS错误(拒绝访问)。这就是本文为什么要把file控件做成透明的,直接接收用户的点击事件的原因。

3 .NET MVC 后台代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
[HttpPost]
public ActionResult UploadImage(HttpPostedFileBase upImg)
{
if (upImg.ContentLength > 0 && upImg.ContentLength / 1024 < 10000)
{
//得到文件的扩展名
string ext = System.IO.Path.GetExtension(upImg.FileName);
if (ext.ToLower() == ".jpg" || ext.ToLower() == ".png" || ext.ToLower() == ".gif")
{
// 没有考虑大规模并发执行的情况,文件名可能重复
string fileName = DateTime.Now.ToString("yyyyMMddHHmmssffff") + System.IO.Path.GetFileName(upImg.FileName);
string filePhysicalPath = Server.MapPath("~/Content/UploadIcon/" + fileName);
string realName = "", error = "";
try
{
upImg.SaveAs(filePhysicalPath);
realName = fileName;
}
catch (Exception ex)
{
error = ex.Message;
return Content("error\\" + error);
}
return Content(fileName);
}
else
{
return Content("error\\不是图片文件,请重新选择!");
}
}
else
{
return Content("error\\文件为空或者超过了8M,请重新选择!");
}
}

参考资料:
CSS - firefox与IE透明度(opacity)设置区别
CSS3中Opacity透明度在IE下的特殊处理