AngularJS 文件上传工具:angular-file-upload

jopen 9年前

angular-file-upload 是一个基于HTML5技术的文件上传轻量级 AngularJS指令(directive),当浏览器不支持时转为采用 FileAPI polyfill技术实现(基于Flash)。

在线演示

特性

  • Supports upload progress, cancel/abort upload while in progress, File drag and drop (html5), Directory drag and drop (webkit), CORS, PUT(html5)/POST methods.
  • Cross browser file upload (HTML5 and non-HTML5) with Flash polyfill FileAPI. Allows client side validation/modification before uploading the file
  • Direct upload to CouchDB, imgur, etc... with file's content type using $upload.http(). This enables progress event for angular http POST/PUT requests. See #88(comment) for discussion and usage.
  • Separate shim file loaded on demand for non-HTML5 code meaning no extra load/code if you just need HTML5 support. (Note that html5-shim.js is still needed for progress event in HTML5 browsers)
  • Lightweight using regular $http to upload (with shim for non-HTML5 browsers) so all angular $http features are available

使用

HTML:

<!-- shim is needed to support upload progress/abort for HTML5 and non-HTML5 FormData browsers.--><!-- angular-file-upload-html5-shim.js could be used instead of angular-file-upload-shim if your app targets HTML5 browsers only (not IE8-9) --><!-- Note: shim.js MUST BE PLACED BEFORE angular.js and angular-file-upload.js AFTER angular.js--><script src="angular-file-upload-shim.min.js"></script>   <script src="angular.min.js"></script>  <script src="angular-file-upload.min.js"></script>     <div ng-controller="MyCtrl">    <input type="text" ng-model="myModelObj">    <input type="file" ng-file-select="onFileSelect($files)">    <input type="file" ng-file-select="onFileSelect($files)" multiple accept="image/*">    <div class="button" ng-file-select="onFileSelect($files)" data-multiple="true"></div>    <div ng-file-drop="onFileSelect($files)" ng-file-drag-over-class="optional-css-class-name-or-function"          ng-show="dropSupported">drop files here</div>    <div ng-file-drop-available="dropSupported=true"           ng-show="!dropSupported">HTML5 Drop File is not supported!</div>    <button ng-click="upload.abort()">Cancel Upload</button>  </div>

JS:

//inject angular file upload directives and service.angular.module('myApp', ['angularFileUpload']);var MyCtrl = [ '$scope', '$upload', function($scope, $upload) {    $scope.onFileSelect = function($files) {    //$files: an array of files selected, each file has name, size, and type.      for (var i = 0; i < $files.length; i++) {      var file = $files[i];        $scope.upload = $upload.upload({          url: 'server/upload/url', //upload.php script, node.js route, or servlet url          //method: 'POST' or 'PUT',          //headers: {'header-key': 'header-value'},          //withCredentials: true,          data: {myObj: $scope.myModelObj},          file: file, // or list of files ($files) for html5 only          //fileName: 'doc.jpg' or ['1.jpg', '2.jpg', ...] // to modify the name of the file(s)          // customize file formData name ('Content-Disposition'), server side file variable name.           //fileFormDataName: myFile, //or a list of names for multiple files (html5). Default is 'file'           // customize how data is added to formData. See #40#issuecomment-28612000 for sample code          //formDataAppender: function(formData, key, val){}        }).progress(function(evt) {        console.log('percent: ' + parseInt(100.0 * evt.loaded / evt.total));        }).success(function(data, status, headers, config) {        // file is uploaded successfully          console.log(data);        });      //.error(...)        //.then(success, error, progress);         // access or attach event listeners to the underlying XMLHttpRequest.        //.xhr(function(xhr){xhr.upload.addEventListener(...)})      }    /* alternative way of uploading, send the file binary with the file's content-type.       Could be used to upload files to CouchDB, imgur, etc... html5 FileReader is needed.        It could also be used to monitor the progress of a normal http post/put request with large data*/      // $scope.upload = $upload.http({...})  see 88#issuecomment-31366487 for sample code.    };  }];

 

Order of scripts: angular-file-upload-shim.js must be loaded before angular.js and is only needed if you are supporting non-HTML5 FormData browsers or you need to support upload progress or cancel.

Upload multiple files: Only for HTML5 FormData browsers (not IE8-9) if you pass an array of files to file option it will upload all of them together in one request. In this case the fileFormDataName could be an array of names or a single string. For Rails or depending on your server append square brackets to the end (i.e. file[]). If you want a cross browser approach you need to iterate through files and upload them one by one like the code above. This is due to the limitation of Flash file upload.

$upload.http(): You can also use $upload.http() to send the file binary or any data to the server while being able to listen to progress event. See #88 for more details. This equivalent to angular $http() but allow you to listen to progress event for HTML5 browsers.

drag and drop styling: For file drag and drop, ng-file-drag-over-class can be a function that returns a class name based on the $event. See the demo for a sample. If the attribute is not specified by default the element will have "dragover" class on drag over which could be used to style the drop zone. You can also specify ng-file-drag-over-delay to fix css3 transition issues from dragging over/out/over #277.

旧的浏览器

对于不支持HTML5 FormData (IE8, IE9, ...) 的旧浏览器,使用 FileAPI 模块。注意:浏览器需要安装Flash,因为FileAPI使用Flash来上传文件。

For these browsers these two files are needed: FileAPI.min.js, FileAPI.flash.swf which will be loaded if the browser does not supports HTML5 FormData (no extra load for HTML5 browsers).

You can put these two files beside angular-file-upload-shim(.min).js on your server to be loaded automatically on demand or optionally you can use the following script to set the FileAPI load path if they are not at the same location:

<script>      //optional need to be loaded before angular-file-upload-shim(.min).js      FileAPI = {          //only one of jsPath or jsUrl.          jsPath: '/js/FileAPI.min.js/folder/',           jsUrl: 'yourcdn.com/js/FileAPI.min.js',            //only one of staticPath or flashUrl.          staticPath: '/flash/FileAPI.flash.swf/folder/',          flashUrl: 'yourcdn.com/js/FileAPI.flash.swf',            //forceLoad: true, html5: false //to debug flash in HTML5 browsers      }  </script>  <script src="angular-file-upload-shim.min.js"></script>...

Old browsers known issues:

  • Because of a Flash limitation/bug if the server doesn't send any response body the status code of the response will be always 204 'No Content'. So if you have access to your server upload code at least return a character in the response for the status code to work properly.
  • Custom headers will not work due to a Flash limitation #111 #224 #129
  • Due to Flash bug #92 Server HTTP error code 400 will be returned as 200 to the client. So avoid returning 400 on your server side for upload response otherwise it will be treated as a success response on the client side.
  • In case of an error response (http code >= 400) the custom error message returned from the server may not be available. For some error codes flash just provide a generic error message and ignores the response text. #310

服务器端的各种实现

Java

You can find the sample server code in Java/GAE here

Node.js

Sample wiki page provided by chovy

Rails

[ToDo] Please contribute if you have working sample.
Rails progress event: If your server is Rails and Apache you may need to modify server configurations for the server to support upload progress. See #207

PHP

[ToDo] Please contribute if you have working sample.

.Net

Sample client and server code demo/C# provided by AtomStar

项目主页:http://www.open-open.com/lib/view/home/1414976636137