如題所示,實現一個Ajax模式的檔案上傳有多難?這並不是一個疑問句,這是一個反問句。
在這裡我先聲明,不要認為一提到Ajax就是講XHttpRequest, Ajax還要包括基於frame的操作,對!我說的是古老的frame。
xhttpRequest並不能實現檔案上傳,所以涉及到檔案的上傳,我們還得回到frame上,尤其是iframe。
需要的材料:
1,你掌握基本的Javascript技能。
2,一個隱藏的form和iframe,這裡我分別命名為uploadForm和uploadResponse.
3,一個負責接收檔案的頁面,名字叫做UploadImage.aspx。
4,一個負責顯示檔案的頁面,名字叫做File.aspx。
基本原理:
通過複製當前form(form1)中的input type=file 的html元素到另一個專用於檔案上傳的form(uploadForm)中,而切uploadForm的target指向到一個隱藏的iframe(uploadResponse)架構的name.這樣,當執行uploadForm的submit()操作時,就會通過uploadResponse將uploadForm的內容post到UploadImage.aspx頁面去執行,由於iframe元素uploadResponse及form元素uploadForm元素都是位於一個隱藏的div元素中,所以訪問者自始至終都不會見到多餘的東西。
執行個體:
Default.aspx頁面。
<script type="text/javascript">
function uploadImage() {
var file = document.getElementById("imageFile");
var uploadFormElement = document.getElementById("uploadForm");
//顯示進度條
document.getElementById("processDiv").style.display = "block"; // the progress div
//複製圖片資料
uploadFormElement.removeChild(uploadFormElement.imageFile);
uploadFormElement.appendChild(file);
document.getElementById("uploadImageDiv").innerHTML = '<input type="file" id="imageFile" name="imageFile" />';
//提交圖片資料
uploadFormElement.submit();
}
function uploadImageResponse(response) {
document.getElementById("processDiv").style.display = "none"; // hide progresss div
var errLabel = document.getElementById("uploadMessage");
errLabel.innerHTML = "";
window.eval("var k=" + response);
if (k.status == 1)
errLabel.innerHTML = k.message;
else if (k.status == 2)
errLabel.innerHTML = k.message;
else
eval("tinyMCE.activeEditor.dom.add(tinyMCE.activeEditor.getBody(), 'img', { src:'" + k.message + "',style:'border:0px; '}, null); ");
}
function uploadButton_onclick() {
}
</script>
<form id="form1" runat="server">
<div>
<!-- Gets replaced with TinyMCE, remember HTML in a textarea should be encoded -->
<tinymce:TextArea ID="elm1" theme="advanced" plugins="spellchecker,safari,pagebreak,style,layer,table,save,advhr,advimage,advlink,emotions,iespell,inlinepopups,insertdatetime,preview,media,searchreplace,print,contextmenu,paste,directionality,fullscreen,noneditable,visualchars,nonbreaking,xhtmlxtras,template"
theme_advanced_buttons1="bold,italic,underline,strikethrough,|,justifyleft,justifycenter,justifyright,justifyfull,|,fontselect,fontsizeselect,forecolor,backcolor,image"
theme_advanced_buttons2="" theme_advanced_buttons3="" theme_advanced_buttons4=""
theme_advanced_toolbar_location="top" theme_advanced_toolbar_align="left" theme_advanced_path_location="bottom"
theme_advanced_resizing="true" runat="server" />
<div style="margin-top: 5px">
上傳圖片:
<br />
<div id="uploadImageDiv">
<input type="file" id="imageFile" name="imageFile" /></div>
<input type="button" id="uploadButton" onclick="uploadImage(); " value="上傳" />
<span id="uploadMessage" style="border: 1px solid #cccccc; color: Red; "></span>
</div>
<div id="processDiv" style="display: none; color: #660066; font-family: Arial; ">
<img src="http://images.cnblogs.com/loading2.gif" alt="uploading" />
圖片上傳中 <span id="fileName" />
</div>
</div>
</form>
<div style="display: none; ">
<iframe name="uploadResponse"></iframe>
<form id="uploadForm" action="UploadImage.aspx?t=<%= DateTime.Now.Ticks %>" target="uploadResponse"
method="post" enctype="multipart/form-data">
<input type="file" name="imageFile" value="" />
</form>
</div>
如上所示,首先選擇準備上傳的檔案,然後當你點擊上傳按鈕(name為uploadButton)時,調用uploadImage函數,該函數的作用是複製form1的input type=file的imageFile元素到uploadForm中,並替換原始的imageFile的outerhtml(原因是javascript不支援修改input type=file的元素的value屬性),當然還有顯示可愛的上傳進度條(這樣顯得我們既專業又酷)。
function uploadImage() {
var file = document.getElementById("imageFile");
var uploadFormElement = document.getElementById("uploadForm");
//顯示進度條
document.getElementById("processDiv").style.display = "block"; // the progress div
//複製圖片資料
uploadFormElement.removeChild(uploadFormElement.imageFile);
uploadFormElement.appendChild(file);
document.getElementById("uploadImageDiv").innerHTML = '<input type="file" id="imageFile" name="imageFile" />';
//提交圖片資料
uploadFormElement.submit();
}
當使用者點擊上傳按鈕時,工作轉由UploadImage.aspx程式接手。
protected void Page_Load(object sender, EventArgs e)
{
Page.Response.Cache.SetCacheability(HttpCacheability.NoCache);
int status = 0; //狀態
string message = ""; //反饋資訊
//檢查檔案
if (Request.Files.Count == 0)
{
status = 1;
message = "請先選擇要上傳的檔案";
RenderUploadScript(status, message);
}
string ext = Path.GetExtension(Request.Files[0].FileName).ToLower();
if (ext != ".jpg" && ext != ".jpeg")
{
status = 2;
message = "抱歉,目前僅支援jpg格式的圖片";
RenderUploadScript(status, message);
}
Guid fileID = Guid.NewGuid();
string fileName = Server.MapPath(String.Format("~\Files\{0}.jpg",fileID));
Request.Files[0].SaveAs(fileName);
//記錄到當前頁面
RenderUploadScript(0,String.Format( "File.aspx?key={0}",fileID));
}
private void RenderUploadScript(int status, string mess)
{
string script = string.Format("<script language='javascript'> window.parent.uploadImageResponse("{{ status:{0},message:'{1}'}}"); </script>", status, mess);
Response.Write(script);
Response.End();
}
通過HttpWebRequest對象,我們能夠獲得任何由用戶端post或get到伺服器端的資料,UploadImage.aspx頁面的工作很簡單,只負責接收post過來的檔案,並儲存到指定的位置(方便示範,我僅僅使用了SaveAs)。
另外,要注意到一點,由於是Ajax模式的檔案上傳,意味著你的程式要通過javascript反饋系統出現的問題,這裡我通過一個名稱為status的參數來返回出現的問題,0則為一切正常,1則為使用者沒有提供檔案,2則為使用者沒有上傳我指定的檔案類型。
當使用者上傳的檔案沒有任何問題的時候,系統儲存檔案並返回狀態0,並附加檔案的顯示路徑,其他狀態附屬的資訊則是錯誤資訊。
現在回到Default.aspx來看如何接收UploadImage.aspx反饋回來的資訊,這裡要考慮到UploadImage.aspx是個頁面,而且隸屬與iframe元素uploadResponse,所以我們通過javascipt來訪問uploadResponse的所屬window的對象或函數的寫法如下:
"<script language='javascript'> window.parent.uploadImageResponse("{{ status:0,message:'File.aspx?key=guid'}}"); <script>"
Default的接應指令碼則如下:
function uploadImageResponse(response) {
document.getElementById("processDiv").style.display = "none"; // hide progresss div
var errLabel = document.getElementById("uploadMessage");
errLabel.innerHTML = "";
window.eval("var k=" + response);
if (k.status == 1)
errLabel.innerHTML = k.message;
else if (k.status == 2)
errLabel.innerHTML = k.message;
else
eval("tinyMCE.activeEditor.dom.add(tinyMCE.activeEditor.getBody(), 'img', { src:'" + k.message + "',style:'border:0px; '}, null); ");
}
僅僅是在對應的htm編輯器的內容中插入message附帶的資訊。
ok!!主要的痛點我們都解決了。下面則是要讓我們能夠看到我們傳上去的檔案,如果不能即時看到,這個Ajax 檔案上傳就沒啥意義了。
File.aspx頁面的功能代碼如下:
protected void Page_Load(object sender, EventArgs e)
{
Guid key = new Guid(Request.QueryString["key"]);
//圖片所在路徑
string fileName = Server.MapPath(String.Format("~/Files/{0}.jpg", key));
// Send the file
Response.ContentType = "image/jpeg";
Response.WriteFile(fileName, true);
Response.AddFileDependency(fileName);
Response.Cache.SetCacheability(HttpCacheability.Public);
Response.Cache.SetAllowResponseInBrowserHistory(true);
}
OK!一切都完成了。
示範程式:
http://files.cnblogs.com/csharpsharper/CoolThingsShow.rar