建立基于AJAX样式的文件上传
本文为翻译的,原文忘记了,google一下应该找到 呵呵
建立基于AJAX样式的文件上传
如果你访问ASP.NET AJAX 论坛,你会发现有成百的人询问当把File控件放到UpdatePanel里时,并不能够产生具有AJAX上传的效果。这肯定是不能够产生AJAX效果的,因为XMLHTTPRequest对象在内部上传数据时不支持这个功能。在本文我将给大家演示一个具有AJAX效果的文件上传方式。技巧很简单,我将使用iframe框架来上传文件,这样就不会刷新页面,并且在页面 上传过程中,他还会粗略的显示进度,下面是运行的截图
下面让我们详细介绍一下执行过程。就从main页面开始吧
<fieldset>
<legend>Photo Upload Demo</legend>
<div id="divFrame">
<iframe id="ifrPhoto" onload="initPhotoUpload()" scrolling="no" frameborder="0" hidefocus="true" style="text-align:center;vertical-align:middle;border-style:none;margin:0px;width:100%;height:55px" src="PhotoUpload.aspx"></iframe>
</div>
<div id="divUploadMessage" style="padding-top:4px;display:none"></div>
<div id="divUploadProgress" style="padding-top:4px;display:none">
<span style="font-size:smaller">Uploading photo...</span>
<div>
<table border="0" cellpadding="0" cellspacing="2" style="width:100%">
<tbody>
<tr>
<td id="tdProgress1"> </td>
<td id="tdProgress2"> </td>
<td id="tdProgress3"> </td>
<td id="tdProgress4"> </td>
<td id="tdProgress5"> </td>
<td id="tdProgress6"> </td>
<td id="tdProgress7"> </td>
<td id="tdProgress8"> </td>
<td id="tdProgress9"> </td>
<td id="tdProgress10"> </td>
</tr>
</tbody>
</table>
</div>
</div>
</fieldset>
正如你所看到的,我使用了一些div来显示或者隐藏上传页面的信息与进度,并且最为重要的是我在iframe的onload事件里绑定了initPhotoUpload方法,下面就看看iframe对应页面的内容
<form id="photoUpload" enctype="multipart/form-data" runat="server">
<div>
<input id="filPhoto" type="file" runat="server"/>
</div>
<div id="divUpload" style="padding-top:4px">
<input id="btnUpload" type="button" value="Upload Photo" />
</div>
</form>The iframe
在iframe页面里包含了一个上传控件和一个button提交按钮,现我们看一下initPhotoUpload 函数,他是怎么执行的
function initPhotoUpload()
{
_divFrame = document.getElementById('divFrame');
_divUploadMessage = document.getElementById('divUploadMessage');
_divUploadProgress = document.getElementById('divUploadProgress');
_ifrPhoto = document.getElementById('ifrPhoto');
var btnUpload = _ifrPhoto.contentWindow.document.getElementById('btnUpload');
btnUpload.onclick = function(event)
{
var filPhoto = _ifrPhoto.contentWindow.document.getElementById('filPhoto');
//Baisic validation for Photo
_divUploadMessage.style.display = 'none';
if (filPhoto.value.length == 0)
{
_divUploadMessage.innerHTML = '<span style=\"color:#ff0000\">Please specify the file.</span>';
_divUploadMessage.style.display = '';
filPhoto.focus();
return;
}
var regExp = /^(([a-zA-Z]:)|(\\{2}\w+)\$?)(\\(\w[\w].*))(.jpg|.JPG|.gif|.GIF|.png|.PNG|.bmp|.BMP)$/;
if (!regExp.test(filPhoto.value)) //Somehow the expression does not work in Opera
{
_divUploadMessage.innerHTML = '<span style=\"color:#ff0000\">Invalid file type. Only supports jpg, gif, png and bmp.</span>';
_divUploadMessage.style.display = '';
filPhoto.focus();
return;
}
beginPhotoUploadProgress();
_ifrPhoto.contentWindow.document.getElementById('photoUpload').submit();
_divFrame.style.display = 'none';
}
}
一旦加载iframe框架,我们就执行一些变量,这些变量都是以_为前缀来作为DOM的元素。我们同样添加了对iframe里button提交事件的引用。在click事件里,首先验证上传文件是否为空,我们还验证图片的类型,一段这些验证通过,我们将调用beginPhotoUploadProgress 方法来处理上传文件的过程,下面是beginPhotoUploadProgress
function beginPhotoUploadProgress()
{
_divUploadProgress.style.display = '';
clearPhotoUploadProgress();
_photoUploadProgressTimer = setTimeout(updatePhotoUploadProgress, PROGRESS_INTERVAL);
}
function clearPhotoUploadProgress()
{
for (var i = 1; i <= _maxLoop; i++)
{
document.getElementById('tdProgress' + i).style.backgroundColor = 'transparent';
}
document.getElementById('tdProgress1').style.backgroundColor = PROGRESS_COLOR;
_loopCounter = 1;
}
function updatePhotoUploadProgress()
{
_loopCounter += 1;
if (_loopCounter <= _maxLoop)
{
document.getElementById('tdProgress' + _loopCounter).style.backgroundColor = PROGRESS_COLOR;
}
else
{
clearPhotoUploadProgress();
}
if (_photoUploadProgressTimer)
{
clearTimeout(_photoUploadProgressTimer);
}
_photoUploadProgressTimer = setTimeout(updatePhotoUploadProgress, PROGRESS_INTERVAL);
}
你可能已经看到,我们基本的想法是使用timer(window.setTimeout)来显示上传的进度,下载我们看看服务器的代码
private const string SCRIPT_TEMPLATE = "<" + "script " + "type=\"text/javascript\">window.parent.photoUploadComplete('{0}', {1});" + "<" + "/script" + ">";
private void Page_Load(object sender, EventArgs e)
{
if (IsPostBack)
{
//Sleeping for 10 seconds, fake delay, You should not it try at home.
System.Threading.Thread.Sleep(10 * 1000);
UploadPhoto();
}
}
private void UploadPhoto()
{
string script = string.Empty;
if ((filPhoto.PostedFile != null) && (filPhoto.PostedFile.ContentLength > 0))
{
if (!IsValidImageFile(filPhoto))
{
script = string.Format(SCRIPT_TEMPLATE, "The uploaded file is not a valid image file.", "true");
}
}
else
{
script = string.Format(SCRIPT_TEMPLATE, "Please specify a valid file.", "true");
}
if (string.IsNullOrEmpty(script))
{
//Uploaded file is valid, now we can do whatever we like to do, copying it file system,
//saving it in db etc.
//Your Logic goes here
script = string.Format(SCRIPT_TEMPLATE, "Photo uploaded.", "false");
}
//Now inject the script which will fire when the page is refreshed.
ClientScript.RegisterStartupScript(this.GetType(), "uploadNotify", script);
}
private static bool IsValidImageFile(HtmlInputFile file)
{
try
{
using (Bitmap bmp = new Bitmap(file.PostedFile.InputStream))
{
return true;
}
}
catch (ArgumentException)
{
//throws exception if not valid image
}
return false;
}
在服务器上,我们同样执行了一些基本的验证,另外还我们还在客户端生成一些脚本,这些脚本将调用main页面里的photoUploadComplete 函数,他用来显示上传是成功还是失败
下面是photoUploadComplete 代码
function photoUploadComplete(message, isError)
{
clearPhotoUploadProgress();
if (_photoUploadProgressTimer)
{
clearTimeout(_photoUploadProgressTimer);
}
_divUploadProgress.style.display = 'none';
_divUploadMessage.style.display = 'none';
_divFrame.style.display = '';
if (message.length)
{
var color = (isError) ? '#ff0000' : '#008000';
_divUploadMessage.innerHTML = '<span style=\"color:' + color + '\;font-weight:bold">' + message + '</span>';
_divUploadMessage.style.display = '';
if (isError)
{
_ifrPhoto.contentWindow.document.getElementById('filPhoto').focus();
}
}
}
该函数很简单,具体看源代码吧 code