MVC中基於Ajax和HTML5實現檔案上傳功能_AJAX相關

來源:互聯網
上載者:User

引言

在實際編程中,經常遇到實現檔案上傳並顯示上傳進度的功能,基於此目的,本文就為大家介紹不使用flash 或任何上傳檔案的外掛程式來實現帶有進度顯示的檔案上傳功能。

準系統:實現帶有進度條的檔案上傳功能

進階功能:通過拖拽檔案的操作實現多個檔案上傳功能

背景

HTML5提供了一種標準的訪問本地檔案的方法——File API規格說明,通過調用File API 能夠訪問檔案資訊,也可以利用用戶端來驗證上傳檔案的類型和大小是否規範。

該規格說明包含以下幾個介面來使用檔案:

File介面:具有檔案的“讀許可權”,可以擷取檔案名稱,類型,大小等。

FileList介面:指單獨選定的檔案清單,可以通過<input type="file">或拖拽呈現在使用者介面供使用者選擇。

XMLHTTPRequest2是HTML5的無名英雄,XHR2與XMLHttpRequest大體相同,但同時也添加了很多新功能,如下:

1. 增加了上傳/下載位元據

2. 增加了上傳過程中Progess (進度條)事件,該事件包含多部分的資訊:

Total:整型值,用於指定傳輸資料的總位元組數。
Loaded:整型值,用於指定上傳的位元組。
lengthComputable:Bool值用於檢測上傳檔案大小是否可計算。

3. 跨資源共用請求

這些新特性都使得Ajax和HTML5很好的協作,讓檔案上傳變得非常簡單,不再需要使用Flash Player、外部外掛程式或html的<form>標籤就可以完成,根據伺服器端就可以顯示上傳進度條。

本文會編寫一個小型應用程式,能夠實現以下功能:

上傳單個檔案,提供上傳進度資訊顯示。
將圖片發送到伺服器時,建立映像縮圖。
通過檔案清單或拖拽操作實現多個檔案上傳。
首先我們需要檢驗瀏覽器是否支援XHR2,File API,FormData及拖拽操作。

編寫代碼

如何上傳單個檔案並顯示上傳進度?

首先需要做的是建立簡單的View :

定義一個表單,由輸入檔案元素和提交按鈕組成。

使用Bootstrap 進度條顯示進度。

<div id="FormContent">        <form id="FormUpload"        enctype="multipart/form-data" method="post">          <span class="btn btn-success fileinput-button">            <i class="glyphicon glyphicon-plus"></i>            <span>Add files...</span>            <input type="file"            name="UploadedFile" id="UploadedFile" />          </span>          <button class="btn btn-primary start"          type="button" id="Submit_btn">            <i class="glyphicon glyphicon-upload"></i>            <span>Start upload</span>          </button>          <button class="btn btn-warning cancel"          type="button" id="Cancel_btn">            <i class="glyphicon glyphicon-ban-circle"></i>            <span>close</span>          </button>        </form>        <div class="progress CustomProgress">          <div id="FileProgress"          class="progress-bar" role="progressbar"      aria-valuenow="" aria-valuemin=""      aria-valuemax="" style="width %;">            <span></span>          </div>        </div>        <div class="InfoContainer">          <div id="Imagecontainer"></div>          <div id="FileName" class="info">          </div>          <div id="FileType" class="info">          </div>          <div id="FileSize" class="info">          </div>        </div>      </div>

在Onchange 事件中添加輸入檔案元素,並在JS方法SingleFileSelected使用,因此在使用者選擇和修改檔案時都會調用此方法。在該方法中,我們將選擇輸入檔案元素和訪問FileList的檔案對象,選擇第一個檔案files[0],因此我們可以得到檔案名稱,檔案類型等資訊。

 function singleFileSelected(evt) {     //var selectedFile = evt.target.files can use this or select input file element      //and access it's files object     var selectedFile = ($("#UploadedFile"))[].files[];//FileControl.files[];     if (selectedFile) {       var FileSize = ;       var imageType = /image.*/;       if (selectedFile.size > ) {         FileSize = Math.round(selectedFile.size * / ) / + " MB";      }      else if (selectedFile.size > ) {        FileSize = Math.round(selectedFile.size * / ) / + " KB";      }      else {        FileSize = selectedFile.size + " Bytes";      }      // here we will add the code of thumbnail preview of upload images            $("#FileName").text("Name " + selectedFile.name);      $("#FileType").text("type " + selectedFile.type);      $("#FileSize").text("Size " + FileSize);    }  }

可以通過File reader對象從記憶體讀取上傳檔案內容。reader 對象提供很多事件,onload,onError以及四種讀取資料的函數readAsBinaryString(), readAsText(),readAsArrayBuffer(), readAsDataURL(),result屬性工作表示檔案內容。該屬性只有當讀操作執行完成後才有效,資料格式根據調用的初始化讀操作制定的。

在這裡就不詳細解釋File reader,我們會在SingleFileSelected 方法中使用,用於預覽映像,查看代碼:

 if (selectedFile.type.match(imageType)) {        var reader = new FileReader();        reader.onload = function (e) {          $("#Imagecontainer").empty();          var dataURL = reader.result;          var img = new Image()          img.src = dataURL;          img.className = "thumb";          $("#Imagecontainer").append(img);        };        reader.readAsDataURL(selectedFile);      }

到現在為止,就可看到下圖:

現在需要將已上傳的檔案發送到伺服器,因此添加Onclick事件,並在JS uploadFile()方法中調用,代碼如下:

function UploadFile() {     //we can create form by passing the form to Constructor of formData object     //or creating it manually using append function      //but please note file name should be same like the action Parameter     //var dataString = new FormData();     //dataString.append("UploadedFile", selectedFile);        var form = $('#FormUpload')[];     var dataString = new FormData(form);    $.ajax({      url '/Uploader/Upload', //Server script to process data      type 'POST',      xhr function () { // Custom XMLHttpRequest        var myXhr = $.ajaxSettings.xhr();        if (myXhr.upload) { // Check if upload property exists          //myXhr.upload.onprogress = progressHandlingFunction          myXhr.upload.addEventListener('progress', progressHandlingFunction,           false); // For handling the progress of the upload        }        return myXhr;      },      //Ajax events      success successHandler,      error errorHandler,      completecompleteHandler,      // Form data      data dataString,      //Options to tell jQuery not to process data or worry about content-type.      cache false,      contentType false,      processData false    });  }

在該方法中,發送表單,使用Form 資料對象來序列化檔案值,我們可以手動建立formdata資料的執行個體化,通過調用append()方法將域值掛起,或是通過檢索HTML 表單的FormData對象。

progressHandlingFunction方法會提供檢驗上傳檔案Size 是否可計算,使用e.loaded和e.total計算出已上傳百分之多少的資料。

function progressHandlingFunction(e) {     if (e.lengthComputable) {       var percentComplete = Math.round(e.loaded * / e.total);       $("#FileProgress").css("width",        percentComplete + '%').attr('aria-valuenow', percentComplete);       $('#FileProgress span').text(percentComplete + "%");     }     else {       $('#FileProgress span').text('unable to compute');    }  }

現在已經實現了基本的發送資料及提供進度條的功能,接下來需要實現伺服器端的代碼處理,使用upload action方法和uplpader controller 。

在upload 方法中,可以從HttpPostedfileBase對象中擷取檔案資訊,該對象包含上傳的檔案的基本資料如Filename屬性,Contenttype屬性,inputStream屬性等內容,這些資訊都可以用來驗證伺服器端接收的檔案是否有錯,也可以用來儲存檔案。        

 public JsonResult Upload(HttpPostedFileBase uploadedFile)       {         if (uploadedFile != null && uploadedFile.ContentLength > )         {           byte[] FileByteArray = new byte[uploadedFile.ContentLength];           uploadedFile.InputStream.Read(FileByteArray, , uploadedFile.ContentLength);           Attachment newAttchment = new Attachment();          newAttchment.FileName = uploadedFile.FileName;          newAttchment.FileType = uploadedFile.ContentType;          newAttchment.FileContent = FileByteArray;          OperationResult operationResult = attachmentManager.SaveAttachment(newAttchment);          if (operationResult.Success)          {            string HTMLString = CaptureHelper.RenderViewToString            ("_AttachmentItem", newAttchment, this.ControllerContext);            return Json(new            {              statusCode = ,              status = operationResult.Message,              NewRow = HTMLString            }, JsonRequestBehavior.AllowGet);          }          else          {            return Json(new            {              statusCode = ,              status = operationResult.Message,              file = uploadedFile.FileName            }, JsonRequestBehavior.AllowGet);          }        }        return Json(new        {          statusCode = ,          status = "Bad Request! Upload Failed",          file = string.Empty        }, JsonRequestBehavior.AllowGet);      }

 能否通過拖拽操作實現多個檔案上傳的功能?

在這一部分,實現相同的uploader,並為uploader添加一些新功能:

允許選擇多個檔案
拖拽操作
現在給Uplodaer View添加新功能:

為輸入檔案元素添加多個屬性,實現同時選擇多個檔案。

添加實現拖拽功能的檔案,如以下代碼所示:

 <div id="drop_zone">Drop images Here</div>

在JS方法MultiplefileSelected中添加onChange事件,與之前SingleFileSelected的寫法類似,不同的是需要將所有的檔案列出,並允許拖拽檔案。代碼如下:

 function MultiplefileSelected(evt) {     evt.stopPropagation();     evt.preventDefault();     $('#drop_zone').removeClass('hover');     selectedFiles = evt.target.files || evt.dataTransfer.files;     if (selectedFiles) {       $('#Files').empty();       for (var i = ; i < selectedFiles.length; i++) {         DataURLFileReader.read(selectedFiles[i], function (err, fileInfo) {          if (err != null) {            var RowInfo = '<div id="File_' + i + '"             class="info"><div class="InfoContainer">' +                    '<div class="Error">' + err + '</div>' +                   '<div data-name="FileName"                    class="info">' + fileInfo.name + '</div>' +                   '<div data-type="FileType"                    class="info">' + fileInfo.type + '</div>' +                   '<div data-size="FileSize"                    class="info">' + fileInfo.size() +                    '</div></div><hr/></div>';            $('#Files').append(RowInfo);          }          else {            var image = '<img src="' + fileInfo.fileContent +             '" class="thumb" title="' +             fileInfo.name + '" />';            var RowInfo = '<div id="File_' + i + '"             class="info"><div class="InfoContainer">' +                   '<div data_img="Imagecontainer">' +                    image + '</div>' +                   '<div data-name="FileName"                    class="info">' + fileInfo.name + '</div>' +                   '<div data-type="FileType"                    class="info">' + fileInfo.type + '</div>' +                   '<div data-size="FileSize"                    class="info">' + fileInfo.size() +                    '</div></div><hr/></div>';            $('#Files').append(RowInfo);          }        });      }    }  }

在該方法中,將選擇和拖拽檔案操作的變數設定為全域變數selectedFiles,然後掃描 selectedfiles中的每個檔案,將從 DataURLreader對象中調用Read 方法讀取檔案。

DataURLreader對象可調用read方法,並將File對象和回調方法作為read方法參數,在上述方法中我們建立了FileReader,並修改了FileReader的Onload和onerror回呼函數。調用 readAsDataURL 方法來讀檔案。

建立FileInfo對象包括了所有的檔案資訊及內容。

 var DataURLFileReader = {     read function (file, callback) {       var reader = new FileReader();       var fileInfo = {         name file.name,         type file.type,         fileContent null,         size function () {           var FileSize = ;          if (file.size > ) {            FileSize = Math.round(file.size * / ) / + " MB";          }          else if (file.size > ) {            FileSize = Math.round(file.size * / ) / + " KB";          }          else {            FileSize = file.size + " bytes";          }          return FileSize;        }      };      if (!file.type.match('image.*')) {        callback("file type not allowed", fileInfo);        return;      }      reader.onload = function () {        fileInfo.fileContent = reader.result;        callback(null, fileInfo);      };      reader.onerror = function () {        callback(reader.error, fileInfo);      };      reader.readAsDataURL(file);    }  };

使用拖拽操作選擇

由於大部分瀏覽器現在已經執行拖拽操作,為了實現拖拽操作,在drop_zone 元素中添加dragover和drop事件。

         var dropZone = document.getElementById('drop_zone');
         dropZone.addEventListener('dragover', handleDragOver, false);
         dropZone.addEventListener('drop', MultiplefileSelected, false);
         dropZone.addEventListener('dragenter', dragenterHandler, false);
         dropZone.addEventListener('dragleave', dragleaveHandler, false);

當檔案拖到目標位置時觸發dragover事件,在以下代碼中,我們修改了預設瀏覽器及datatransfer的dropEffect 屬性,代碼如下:

  function handleDragOver(evt) {     evt.preventDefault();     evt.dataTransfer.effectAllowed = 'copy';     evt.dataTransfer.dropEffect = 'copy';   }

接著在MultiplefileSelected中添加drop事件來處理檔案drop操作。

大部分功能已經完善,現在需要添加“上傳按鈕”,通過Onclick事件來調用UploadMultipleFiles方法。

該方法與上文提到的Uploadfile方法類似,不同的是手動驗證formdata對象值。

   function UploadMultipleFiles() {     // here we will create FormData manually to prevent sending mon image files     var dataString = new FormData();     //var files = document.getElementById("UploadedFiles").files;     for (var i = ; i < selectedFiles.length; i++) {       if (!selectedFiles[i].type.match('image.*')) {         continue;       }      }  // AJAX Request code here  }

接下來添加伺服器端處理代碼,與上文添加的代碼類似,需要做的就是接受一系列的檔案清單,如下:

  public JsonResult UplodMultiple(HttpPostedFileBase[] uploadedFiles)

確保 HttpPostedFileBase 數組名稱與append 方法中的名稱相同,只有這樣,MVC才能映射到檔案數組中。

 public JsonResult UplodMultiple(HttpPostedFileBase[] uploadedFiles)
  dataString.append("uploadedFiles", selectedFiles[i]); 

上傳大檔案

為了允許上傳大檔案,如果使用的是 IIS7及以上版本,需要修改Web.config 檔案,添加以下代碼:

<system.webServer>      <security>           <requestFiltering>                <requestLimits maxAllowedContentLength="" />           </requestFiltering>      </security>   </system.webServer>   <httpRuntime targetFramework="." maxRequestLength=""/>

到這裡所有的功能就可以實現了,而且最大可上傳2GB的檔案。

以上內容就是小編給大家介紹的MVC中基於Ajax和HTML5實現檔案上傳功能,希望對大家有所協助。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.