angularjs 实现 文件拖拽,缩略图显示
成果图:
main-hugeScreen.html
<div class="hbox hbox-auto-xs hbox-auto-sm" ng-controller="HugeScreenCtrl"> <!--div ng-controller="HugeScreenCtrl"> <div class="col w-lg bg-light b-r bg-auto"> <div class="wrapper-md dker b-b"> <h3 class="m-n font-thin">选择文件</h3> </div> <div class="wrapper-md"> <p>多个文件</p> <input type="file" multiple/> <p class="m-t-md">单个文件</p> <input type="file"/> </div> </div> <div> <input type="file" file-model="myFile" multiple/> <button ng-click="uploadFile()">upload me</button> </div> </div--> <div class="col w-lg bg-light b-r bg-auto"> <div class="wrapper-md dker b-b"> <h3 class="m-n font-thin">Select files</h3> </div> <div class="wrapper-md"> <div ng-show="true" class="m-b-md"> <!-- 3. nv-file-over uploader="link" over-class="className" --> <div file-dropzone="[image/png, image/jpeg, image/gif]" files="myFile" over-class='b-danger' data-max-file-size="3" class="b-a b-2x b-dashed wrapper-lg bg-white text-center m-b"> Base drop zone </div> <!-- Example: nv-file-drop="" uploader="{Object}" options="{Object}" filters="{String}" --> <div> <div file-dropzone="[image/png, image/jpeg, image/gif]" files="myFile" over-class='b-info' data-max-file-size="3" active="redColorActive" class="b-a b-2x b-dashed wrapper-lg lter text-center" > Another drop zone with its own settings </div> </div> </div> <!-- Example: nv-file-select="" uploader="{Object}" options="{Object}" filters="{String}" --> <p>Multiple</p> <input type="file" file-model="myFile" multiple/> <p class="m-t-md">Single</p> <input type="file" file-model="myFile"/> </div> </div> <div class="col"> <div class="wrapper-md bg-light dk b-b"> <span class="pull-right m-t-xs">Queue length: <b class="badge bg-info">{{myFile.length}}</b></span> <h3 class="m-n font-thin">Upload queue</h3> </div> <div class="wrapper-md"> <table class="table bg-white-only b-a"> <thead> <tr> <th width="30%">缩略图</th> <th width="30%">Name</th> <th ng-show="true">Size</th> <th ng-show="true">Progress</th> <th>Status</th> <th>Actions</th> </tr> </thead> <tbody> <tr ng-repeat="item in myFile"> <!--td><img ng-src={{item.stream}}/></td--> <td><img ng-src={{item.stream}} style="max-width: 200px; max-height: 200px"/></td> <td><strong>{{ item.file.name }}</strong></td> <td ng-show="true" nowrap>{{ item.file.size/1024/1024|number:2 }} MB</td> <td ng-show="true"> <div class="progress progress-sm m-b-none m-t-xs"> <div class="progress-bar bg-info" role="progressbar" ng-style="{ 'width': item.progress + '%' }"></div> </div> </td> <td class="text-center"> <span ng-show="item.isSuccess" class="text-success"><i class="glyphicon glyphicon-ok"></i></span> <span ng-show="item.isCancel" class="text-warning"><i class="glyphicon glyphicon-ban-circle"></i></span> <span ng-show="item.isError" class="text-danger"><i class="glyphicon glyphicon-remove"></i></span> </td> <td nowrap> <button type="button" class="btn btn-default btn-xs" ng-click="item.upload(item)" ng-disabled="item.isReady || item.isUploading || item.isSuccess"> Upload </button> <button type="button" class="btn btn-default btn-xs" ng-click="removeItem($index)"> Remove </button> </td> </tr> </tbody> </table> <div> <div> <p>Queue progress:</p> <div class="progress bg-light dker" style=""> <div class="progress-bar progress-bar-striped bg-info" role="progressbar" ng-style="{ 'width': allprogress + '%' }"></div> </div> </div> <button type="button" class="btn btn-addon btn-success" ng-click="uploadAllfiles(allprogress)"> <i class="fa fa-arrow-circle-o-up"></i> Upload all </button> <button type="button" class="btn btn-addon btn-warning" ng-click="cancelAll()" ng-disabled="!myFile.isUploading"> <i class="fa fa-ban"></i> Cancel all </button> <button type="button" class="btn btn-addon btn-danger" ng-click="clearQueue()" ng-disabled="!myFile.length"> <i class="fa fa-trash-o"></i> Remove all </button> <p class="text-muted m-t-xl">Note: upload.php file included, files will be uploaded to "src/js/controllers/uploads".</p> </div> <div> <table><thead><tr><th>缩略图</th></tr></thead><tbody> <tr ng-repeat="item in image track by $index"> <td> <img ng-src={{item}} /> </td> </tr> </tbody></table> <!-- <span class="file-name">{{imageFileName}}</span>--> </div> </div> </div> </div>
bjt-imageload-service.js
/** * Created by chaiqiaozhen on 10/6/15. */ app.service('fileReader', function ($q) { var fileReader = this; fileReader.onLoad = function(file, reader,deferred, scope) { return function () { scope.$apply(function () { var ret = { srcfile: file, stream: reader.result }; deferred.resolve(ret); }); }; }; fileReader.onError = function (reader, deferred, scope) { return function () { scope.$apply(function () { deferred.reject(reader.result); }); }; }; fileReader.onProgress = function(reader, scope) { return function (event) { scope.$broadcast("fileProgress", { total: event.total, loaded: event.loaded }); }; }; fileReader.getReader = function(file,deferred, scope) { var reader = new FileReader(); reader.onload = fileReader.onLoad(file, reader,deferred, scope); reader.onerror = fileReader.onError(reader, deferred, scope); reader.onprogress = fileReader.onProgress(reader, scope); return reader; }; fileReader.readMyAsDataURL = function (file, scope) { var deferred = $q.defer(); var reader = fileReader.getReader(file, deferred, scope); reader.readAsDataURL(file); return deferred.promise; }; });
hugeScreen-service.js
app.directive('fileDropzone', ['$bjtHttpService','fileReader',function($bjtHttpService,fileReader) { return { restrict: 'A', scope: { files: '=', overClass: '=' }, link: function(scope, element, attrs) { var checkSize, isTypeValid, processDragOverOrEnter, validMimeTypes,getDataTransfer,addfile; var fileList = []; addfile = function(item){ fileList[fileList.length] = item; } getDataTransfer = function(event) { var dataTransfer; return dataTransfer = event.dataTransfer || event.originalEvent.dataTransfer; }; processDragOverOrEnter = function(event) { if (event != null) { event.preventDefault(); } getDataTransfer(event).effectAllowed = 'copy'; element.addClass(attrs.overClass); // console.log(element); return false; }; validMimeTypes = attrs.fileDropzone; checkSize = function(size) { var _ref; if (((_ref = attrs.maxFileSize) === (void 0) || _ref === '') || (size / 1024) / 1024 < attrs.maxFileSize) { return true; } else { alert("File must be smaller than " + attrs.maxFileSize + " MB"); return false; } }; isTypeValid = function(type) { if ((validMimeTypes === (void 0) || validMimeTypes === '') || validMimeTypes.indexOf(type) > -1) { return true; } else { alert("Invalid file type. File must be one of following types " + validMimeTypes); return false; } }; element.bind('dragover', processDragOverOrEnter); element.bind('dragenter', processDragOverOrEnter); return element.bind('drop', function(event) { var files; if (event != null) { event.preventDefault(); } element.removeClass(attrs.overClass); fileList = []; files = getDataTransfer(event).files; for(var i = 0; i < files.length; i++){ if(!isTypeValid(files[i].type)) return false; if(!checkSize(files[i].size)) return false; /* var reader = new FileReader(); reader.onload = function(reader,evt){ console.log(reader); }; reader.readAsDataURL(files[i]);*/ /* fileReader.readMyAsDataURL(files[i],scope).then( function(ret){ console.log(ret); });*/ fileReader.readMyAsDataURL(files[i], scope) .then(function(ret) { var file = { isSuccess: false, isCancel: false, isError: false, progress: 0, isReady: false, isUploading: false, file: ret.srcfile, stream: ret.stream, upload: function (item) { var options = { headers: {'Content-Type': undefined}, callbackError: function(args,data){ item.isError = true; }, callbackSuccess: function(args,data){ item.isSuccess = true; item.progress = 100; console.log(this.isSuccess); } }; var addOptions = { transformRequest: angular.identity }; var fd = new FormData(); fd.append('file', this.file); $bjtHttpService.$post('demo/file/upload',fd,options,addOptions); } }; addfile(file); }); } scope.files = fileList; return false; }); } }; }]); app.directive('fileModel', ['$parse', '$bjtHttpService', function ($parse, $bjtHttpService) { return { restrict: 'A', link: function(scope, element, attrs) { var model = $parse(attrs.fileModel); var modelSetter = model.assign; var filelist = []; element.bind('change', function(){ scope.$apply(function(){ for(var i = 0; i < element[0].files.length; i++){ var file = { isSuccess: false, isCancel: false, isError: false, progress: 0, isReady: false, isUploading: false, file: element[0].files[i], fileStream: null, upload: function (item) { var options = { headers: {'Content-Type': undefined}, callbackError: function(args,data){ item.isError = true; }, callbackSuccess: function(args,data){ item.isSuccess = true; item.progress = 100; console.log(this.isSuccess); } }; var addOptions = { transformRequest: angular.identity }; var fd = new FormData(); fd.append('file', this.file); $bjtHttpService.$post('demo/file/upload',fd,options,addOptions); } }; filelist[i] = file; } modelSetter(scope, filelist); }); }); } }; }]); app.controller('HugeScreenCtrl', ['$scope', 'fileReader', function($scope, fileReader) { $scope.allprogress=0; $scope.myFile = ''; $scope.image= null; $scope.imageFileName = ''; $scope.redColorActive = 'false';//'b-danger'; $scope.removeItem = function(index){ $scope.myFile.splice(index, 1); }; $scope.getNotUploadedItems = function () { var files = []; for(var i = 0, j = 0; i < $scope.myFile.length; i++){ if(!$scope.myFile[i].isSuccess) files[j++] = $scope.myFile[i]; } return files; }; $scope.getImage = function(item){ fileReader.readMyAsDataURL(item, $scope) .then(function(result) { return result; }); }; $scope.uploadAllfiles = function(){ $scope.allprogress = 0.0; console.log($scope.allprogress); var percent = 0; if($scope.myFile.length > 0) percent = 100/$scope.myFile.length; console.log(percent); for( var i = 0; i < $scope.myFile.length; i++) { if($scope.myFile[i].isSuccess) $scope.allprogress = $scope.allprogress+ percent; else{ $scope.myFile[i].upload($scope.myFile[i]); if($scope.myFile[i].isSuccess) $scope.allprogress = $scope.allprogress+ percent; } console.log($scope.allprogress); } }; }]);