常規實現方法:
ajax無法實現上傳檔案,因此常規情況下,要實現無重新整理上傳檔案的做法,是在頁面隱藏一個iframe,然後將上傳form的target指向這個iframe,變相的實現。如下代碼:
<p id="uploading" style="display:none;">Uploading...<img src="loading.gif"/><form action="upload.php" method="post" enctype="multipart/form-data" target="upload_target" onsubmit="startUpload();" > File: <input name="myfile" type="file" /> <input type="submit" name="submitBtn" value="Upload" /></form><iframe id="upload_target" name="upload_target" src="#" style=";height:0;border:0px solid #fff;"></iframe>
upload_target是一個長寬都是0的iframe,所以頁面上看不見他。還需要配合js,使得效果更好:
<script>function startUpload(){ $('#uploading').show();}function finisheUpload(i){ $('#uploading').hide(); if(i==0) { alert("上傳成功"); } else { alert("上傳失敗"); }}</script>
其中startUpload方法是在提交表單的時候觸發,而由於沒有什麼回呼函數,因此finisheUpload只能由upload.php檔案的輸出控制。通常就是在輸出中輸出一段javascript代碼來執行。
php代碼如下:
<?phpheader("Content-Type:text/html;charset=utf-8");$destination_path = getcwd().DIRECTORY_SEPARATOR;$filname = $destination_path . basename( $_FILES['myfile']['name']);$filname=iconv("UTF-8","gb2312",$filname);if(move_uploaded_file($_FILES['myfile']['tmp_name'], $filname)) { echo "<script language=\"javascript\" type=\"text/javascript\">window.parent.finisheUpload(0);</script> ";}else{ echo "<script language=\"javascript\" type=\"text/javascript\">window.parent.finisheUpload(1);</script> ";}
注意,輸出javascript的時候,由於調用的js方法是在iframe外定義的,要在iframe內調用js方法,需要指定window.parent。
————————
HTML5下的實現方法:
先介紹一下FileReader對象:
FileReader對象的詳細說明可以在W3C官方文檔中查看。
該介面提供方法來讀取檔案對象或者Blob對象。它繼承了EventTarget,介面的描述如下:
[Constructor] interface FileReader: EventTarget { // async read methods void readAsArrayBuffer(Blob blob); void readAsText(Blob blob, optional DOMString label); void readAsDataURL(Blob blob); void abort(); // states const unsigned short EMPTY = 0; const unsigned short LOADING = 1; const unsigned short DONE = 2; readonly attribute unsigned short readyState; // File or Blob data readonly attribute (DOMString or ArrayBuffer)? result; readonly attribute DOMError? error; // event handler attributes attribute EventHandler attribute EventHandler onprogress; attribute EventHandler attribute EventHandler onabort; attribute EventHandler onerror; attribute EventHandler };
可以看到有4個非同步方法呼叫,其中3個是讀取,1個是放棄,4個狀態屬性,1個result,1個error和6個事件。之前還有readAsBinaryString方法,不過已經被W3C去除了)這6個事件的觸發時機如下:
loadstart --When the read starts.
progress --While reading (and decoding) blob
abort --When the read has been aborted. For instance, by invoking the abort() method.
error --When the read has failed (see errors).
load --When the read has successfully completed.
loadend --When the request has completed (either in success or failure).
下面示範一個例子,讀取一個文字文件,並且alert出來內容。
<script>function readfile(dom){ var file = dom.files[0]; var textType = /text.*/;//Regex,使之匹配text/html,text/plain if (file.type.match(textType)) { var reader = new FileReader(); //註冊事件函數,即等讀完內容後,要做的事情 reader.onload = function(e) { alert(reader.result); } //非同步讀取內容 reader.readAsText(file,'gb2312'); $("#msg").html("正在執行非同步讀取"); } else { alert("檔案不支援"); }}</script><input type="file" id="testfiles" name="files[]" onchange="readfile(this);" /><div id="msg"></div>
——————————————————————————————
下面示範一個例子,讀取一個DataURL的,DataURL其實是一種DataURI要知道URI的更多細節,可以去http://css-tricks.com/data-uris/,或者維基百科瞭解更多)。它提供了一種在瀏覽器中顯示資料的途徑。比如你要顯示一個圖片百度的logo)的話,你可以如下寫:
<img src="http://www.bkjia.com/uploads/allimg/131229/122455A95-0.gif" />
你也可以用它的URI去寫,如下:
<img src="data:image/gif;base64,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" />
src中填寫的字串就是DataURI,格式如下:
data:[<mime type>][;charset=<charset>][;base64],<encoded data>
這種URI其實很有用的,可以減少HTTP請求,使得網站提速。因此擷取了URI的話就可以載入本地的映像了。範例程式碼如下:
<script>function loadimg(dom){ var file = dom.files[0]; //Regex,使之匹配image/jpeg等 var imageType = /image.*/; if (file.type.match(imageType)) { var reader = new FileReader(); reader.onload = function(e) { var img = new Image(); img.src=\'#\'" $("#divimg").append(img); } reader.readAsDataURL(file); } else { alert("檔案不支援"); }}</script><input type="file" id="testfiles" name="files[]" onchange="loadimg(this);" /><div id="divimg"></div>
————————————————————————————————————
還有一個方法是readAsArrayBuffer,從字面就可以看出,是把檔案讀取到一個數組緩衝區。
使用readAsArrayBuffer這種方法實現上傳檔案
下面示範一個例子:
<script>function upload(){ var file = $('#testfiles')[0].files[0]; var reader = new FileReader(); reader.onload = function (rResult) { var filename = file.name; var options = { type: 'POST', url: 'upload.php?filename='+filename, data: reader.result, success:function(result){ alert(result.msg); }, processData: false, // 告訴jQuery不要去處理髮送的資料 contentType: false, // 告訴jQuery不要去設定Content-Type要求標頭 dataType:"json" }; $.ajax(options); }; reader.readAsArrayBuffer(file);}</script><input type="button" value="upload" onclick="javascript:upload();"/>
後端PHP代碼:
try{ $filename=$_GET['filename']; $input = file_get_contents("php://input"); //這個是擷取請求的InputStream,PHP下的寫法 file_put_contents($filename, $input);//儲存成檔案。 echo json_encode(array("msg"=>"上傳成功"));}catch(Exception $e){ echo json_encode(array("msg"=>"上傳失敗"));}
FormData方法
FromData的官方說明在這裡。利用FormData
對象,你可以使用一系列的索引值對來類比一個完整的表單。
以下給出一個例子,允許上傳多個檔案:
<script>function upload(){ var formdata = new FormData(); $.each($('#testfiles')[0].files, function(i, file) { formdata.append('file-'+i, file); }); var options = { type: 'POST', url: 'upload.php', data: formdata, success:function(result){ alert(result.msg); }, processData: false, // 告訴jQuery不要去處理髮送的資料 contentType: false, // 告訴jQuery不要去設定Content-Type要求標頭 dataType:"json" }; $.ajax(options);}</script><input type="button" value="upload" onclick="javascript:upload();"/>
後台PHP代碼:
try{ foreach($_FILES as $key => $value) { //print_r ($_FILES[$key]); echo "<br>"; move_uploaded_file( $value["tmp_name"], $value['name']); } echo json_encode(array("msg"=>"上傳成功"));}catch(Exception $e){ echo json_encode(array("msg"=>"上傳失敗"));}
參考文檔:
https://developer.mozilla.org/zh-CN/docs/DOM/XMLHttpRequest/FormData/Using_FormData_Objects
http://dev.w3.org/2006/webapi/FileAPI/#FileReader-interface
http://www.w3.org/TR/XMLHttpRequest2/#interface-formdata
http://blog.teamtreehouse.com/reading-files-using-the-html5-filereader-api
http://www.dotblogs.com.tw/junegoat/archive/2013/05/27/test-fileapi-multiupload-readasarraybuffer.aspx
本文出自 “一隻部落格” 部落格,請務必保留此出處http://cnn237111.blog.51cto.com/2359144/1330089