在开发项目的时候须要在一次请求中可以上传多张图片,本觉得使用cordova的相关插件file-transer就能轻松搞定。可是真的想的太简单了,cordova plugin的file-transer一次只能上传一个文件,若是想要用循环的方式,就会再后台产生多条记录显然不是咱们须要的。最后翻了不少博客后加上本身调试终于实现。css
<div class="item row row-wrap"> <div ng-repeat="item in files" class="col col-25"> <div class="pos-relative level-center w60 h60"> <img ng-src="{{item}}"> <i ng-click="deleteFile(item)" class="icon ion-close-circled pos-absolute deleteFile"></i> </div> </div> <div ng-if="files.length < 6" ng-click="showActionSheet()" class="col col-25"> <div class="text-align-center level-center pt5 w60 h60" style="border: 1px solid #b3b3b3;"> <i class="icon ion-plus-round font30"></i> <p ng-bind="i18n.upload_accessory_btn" class="text-align-center font12"></p> </div> </div> </div>
function dealFiles(imageAry) { $ionicLoading.show(); const deferred = $q.defer(), promise = _.map(imageAry, (item, key) => { const def = $q.defer(); // 这里再次使用$q.defer为了确保全部图片已经转化完毕 window.resolveLocalFileSystemURL(item, fileEntry => { fileEntry.file(file => { let reader = new FileReader(); reader.onloadend = e => { const the_file = new Blob([e.target.result ], { type: file.type} ); imgData.append("files" + key, the_file, file.name); def.resolve(item); }; reader.readAsArrayBuffer(file); }); }); return def.promise; }); $q.all(promise).then(result => { deferred.resolve(result); }).catch(reason => { deferred.reject(reason); }); return deferred.promise; } function openImages(num) { const options = { maximumImagesCount: num, width: 600, height: 500, quality: 100 }; $cordovaImagePicker.getPictures(options) .then(results => { $scope.files = _.concat($scope.files, results); }, error => { console.log(error); }); } function takePhoto() { const options = { quality: 100, destinationType: Camera.DestinationType.PHOTOLIBRARY, sourceType: Camera.PictureSourceType.CAMERA, encodingType: Camera.EncodingType.JPEG, targetWidth: 600, targetHeight: 500 }; $cordovaCamera.getPicture(options).then(imageURI => { $scope.files.push(imageURI); }).catch(error => { console.log(error); }); } $scope.files = []; $scope.uploadFiles = data => { dealFiles($scope.files).then(() => { //添加调用接口的的参数 imgData.append("id", data); imgData.append("sid", $scope.userInfo.sid); $http.post(CONFIG.url.upload, imgData, { headers: {"Content-Type": undefined }, transformRequest: angular.identity }).success(() => { $ionicLoading.hide(); console.log("上传成功"); }).error(() => { $ionicLoading.hide(); console.log("请从新上传"); }); } ); }; $scope.showActionSheet = () => { const maxImgNum = 6, imageNum = maxImgNum - $scope.files.length; $ionicActionSheet.show({ buttons: [ {text: "拍照"}, {text: "从相册中选择"} ], cancelText: "取消", cssClass: "touched", cancel() { }, buttonClicked(index) { if (index) { openImages(imageNum); } else { takePhoto(); } return true; } }); };
注意:
一、这里从相册选择照片的时候,咱们能够在options中设置照片最大数目,但仅限于一次调用时,意思就是若是想限制最终的照片数目为6,maximumImagesCount设置为6后,第一次选择了5张,第二次又能够选择6张,最终是超过了咱们数目限制,因此这里的num我是做为num变量传入的。
二、ios不支持maximumImagesCount,这就比较坑了,没办法只能在最终上传的时候,提示用户了
三、不用管是从相册$cordovaImagePicker,仍是用拍照$cordovaCamera获取的uri我都直接放到files这个数组中,在html中能够直接展现
四、这边其实最须要注意的仍是在dealFiles这个函数中,必须确保全部的图片都使用window.resolveLocalFileSystemURL方法将本地选取的图片转为Blob而后追加到FormData中去,而且要保证已经转化追加完毕。(真机调试的时候,一直上传图片失败,没有加$q.defer虽然全部图片都已经调用了resolveLocalFileSystemURL方法,可是尚未转化添加到formdata中)
五、利用angular实现post请求的时候,须要设置 headers: {"Content-Type": undefined },transformRequest: angular.identity
经过anjularjs的http请求来上传文件的,因此要让当前的request成为一个Multipart/form-data请求,anjularjs对于post和get请求默认的Content-Type header 是application/json。经过设置‘Content-Type’: undefined,这样浏览器不只帮咱们把Content-Type 设置为 multipart/form-data,还填充上当前的boundary,若是你手动设置为: ‘Content-Type’: multipart/form-data,后台会抛出异常:the current request boundary parameter is null。 html
参考文章:ios