最近做的项目中用到了angular下上传图片功能,在做的过程中遇到了许多问题,最终都得以解决

angular上传时和普通上传时过程差不多,只不过是要不一些东西转化为angular的东西。

1.ng-file-select,指令angular是没此功能的,其实也是转化成了change事件,不多说,直接上代码

angular.module('myApp')
.directive('ngFileSelect', [ '$parse', '$timeout', function($parse, $timeout) {
return function(scope, elem, attr) {
var fn = $parse(attr['ngFileSelect']); elem.bind('change', function(evt) {
var files = [], fileList, i;
fileList = evt.target.files; if (fileList != null) {
for (i = 0; i < fileList.length; i++) {
files.push(fileList.item(i));
}
}
$timeout(function() {
fn(scope, {
$files : files,
$event : evt
});
});
});
};
}])

2.服务 上传文件前预览并压缩图片功能

//上传文件预览
angular.module('myServers',[])
.factory('fileReader', ['$q', '$log', function($q, $log) {
var dataURItoBlob = function(dataURI) {
// convert base64/URLEncoded data component to raw binary data held in a string
var byteString;
if (dataURI.split(',')[0].indexOf('base64') >= 0)
byteString = atob(dataURI.split(',')[1]);
else
byteString = unescape(dataURI.split(',')[1]); // separate out the mime component
var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0]; // write the bytes of the string to a typed array
var ia = new Uint8Array(byteString.length);
for (var i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
} return new Blob([ia], {
type: mimeString
});
}; var onLoad = function(reader, deferred, scope,file) {
return function() {
scope.$apply(function() {
var img = new Image();
//前端压缩图片
img.onload = function(){
//resize the image using canvas
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
var width = img.width;
var height = img.height; var MAX_WIDTH = width>2500 ? width/2 : 2500;
var MAX_HEIGHT = height>2500 ? height/2 : 2500;
if (width > height) {
if (width > MAX_WIDTH) {
height *= MAX_WIDTH / width;
width = MAX_WIDTH;
}
} else {
if (height > MAX_HEIGHT) {
width *= MAX_HEIGHT / height;
height = MAX_HEIGHT;
}
} canvas.width = width ;
canvas.height = height; ctx.drawImage(img, 0, 0, width, height); var dataURL = canvas.toDataURL('image/jpeg', 1);
var blob = dataURItoBlob(dataURL);
if(blob.size > 2000 * 1024){
dataURL = canvas.toDataURL('image/jpeg', .2);
}else if(blob.size > 1000 * 1024){
dataURL = canvas.toDataURL('image/jpeg', .5); }else{
dataURL = canvas.toDataURL('image/jpeg', .8);
}
blob = dataURItoBlob(dataURL);
deferred.resolve(blob);
}
img.src = URL.createObjectURL(file); });
};
}; var onError = function(reader, deferred, scope) {
return function() {
scope.$apply(function() {
deferred.reject(reader.result);
});
};
}; var onProgress = function(reader, scope) {
return function(event) { scope.$broadcast("fileProgress", {
total: event.total,
loaded: event.loaded
});
};
}; var getReader = function(deferred, scope, file) {
var reader = new FileReader();
reader.onload = onLoad(reader, deferred, scope,file);
reader.onerror = onError(reader, deferred, scope);
reader.onprogress = onProgress(reader, scope);
return reader;
}; var readAsDataURL = function(file, scope) {
var deferred = $q.defer();
var reader = getReader(deferred, scope,file);
reader.readAsDataURL(file); return deferred.promise;
}; return {
readAsDataUrl: readAsDataURL
};
}]);

这里说明一下,部分代码是参考别人的代码(http://blog.csdn.net/zx007fack/article/details/41073601),但是对其中内容做了修改,因为用原来的代码,如果不加前端压缩功能是正常的,前端压缩的话因为要用到canvas, 直接用reader.result在ios上图片的宽高拿到的直接是0,android上是可以的,具体原因不是很确定是不是base64的问题,所以我又直接把file传了进来,然后用原生js的方法新建图片元素拿到宽高,再用Canvas进行压缩,最后转成blob,通过formData传给后台。

3.controller代码

//选择图片后执行的方法
$scope.fileArr = [];
$scope.imgSrcArr = [];var i = 0; //为ios上图片都为image时添加序号
$rootScope.onFileSelect = function(files, event) {
//预览上传图片开始
$rootScope.startLoading();
var $this = angular.element(event.target); angular.forEach(files, function(value, index) {
var fileIn = value;
var fileInName = fileIn.name;
var fileType = fileInName.substring(fileInName.lastIndexOf(".") + 1, fileInName.length); //解决ios下所有图片都为image.jpg的bug
if(fileIn) {
fileInName = fileInName.split('.')[0] + i + '.' + fileType;
i++;
} attachvo.push({
name: fileInName,
type: fileType
}); fileReader.readAsDataUrl(fileIn, $scope)
.then(function(result) {
result.name = fileInName;
$scope.fileArr.push(result);
$scope.imgSrcArr.push(URL.createObjectURL(result));
              //每次上传后清空file框,确保每次都能调用change事件
document.querySelector('.upload').reset(); });
$scope.$on('fileProgress', function(event, data) {
if(data.total == data.loaded) {
$timeout(function() {
//上传图片结束
$rootScope.endLoading();
}, 200) } }); });
$rootScope.showAttachment = false;
};return false; }

这里处理了下图片,在名字上加了序号,因为在ios上每次选择的图片名字都叫image,查找了很多资料,说是safari的bug,后面版本才会解决,暂时只能以这种方式解决了。循环是上传多张图片

3.html代码

<ul class="upload-view-ul">

        <li ng-repeat="src in imgSrcArr" class="pull-left" ng-click="delCurUpload(src)"
ng-class="{'row-last': (($index+1) % 5==0)}">
<span>x</span>
<em ng-if='nrc'>{{formData.attachvo[$index].attachmentType}}</em>
<img ng-src="{{src}}">
</li>
<div class="attachment" pop-type-select ng-if="nrc">+</div> <div class="attachment" ng-if="!nrc">
+
<form class="upload">
<input type="file" name="file[]" ng-file-select="onFileSelect($files, $event)" multiple>
</form>
</div>
</ul>

4.顺便把formdata时代码贴一下,采用H5上传图片的方式

this.FormdataPost = function(pathUrl, formId, formData, files) {
var fd = new FormData();
fd.append('formId', formId);
if(files && angular.isArray(files)) {
files.forEach(function(item) {
fd.append('file', item, item.name);
});
}
fd.append('formData', angular.toJson(formData, true));
var httpConfig = {
headers: {
'Authorization': 'Bearer ' + this.token,
'Content-Type': undefined
},
transformRequest: angular.identity
};
return $http.post(rootUrl + pathUrl, fd, httpConfig).then(function(data) {
return data;
}).catch(function(error) {
$rootScope.interfaceName = pathUrl;
$rootScope.setNewWortStatus({
status: error.status,
errInfo: error.data && error.data.statusInfo || ''
});
return error;
});
}

思路有一点混乱,不知道讲清楚了没有,想起来再添加吧

最新文章

  1. Hibernate 参数设置一览表
  2. AccessHelper 需修改
  3. poj 2653 线段相交
  4. HttpContext.Current.Cache使用文件依赖问题
  5. ADO,OLEDB,ODBC,DAO的区别【转】
  6. angularJs的工具方法
  7. Creating HTML table with vertically oriented text as table header 表头文字方向
  8. SQL2008安装自动退出
  9. 怎么修改路由器地址的默认IP
  10. vs2010打开设计器出现错误
  11. Android SVN开发实战的文件夹结构呈现
  12. 关于服务器的CPU的几个概念学习总结
  13. java 线程方法 ---- join()
  14. PythonStudy——函数对象 Function object
  15. 机器翻译质量评测算法-BLEU
  16. 安装APK时引发INSTALL_PARSE_FAILED_MANIFEST_MALFORMED错误的几种可能(申明:来源于网络)
  17. MySQL-存储过程procedure
  18. Python运行MapReducer程序时所遇异常
  19. 09、win32 转换为 store app
  20. javascript浅拷贝和深拷贝

热门文章

  1. 让VS2010支持HTML5
  2. 关于SharePoint 2010体系架构的几个话题
  3. shell截取字符串方法
  4. 【Java基础】List迭代并修改时出现的ConcurrentModificationException问题
  5. C++中字符串的结尾标志\0
  6. VisualBox会造成VPN连接不上问题
  7. hdoj 2803 The MAX【简单规律题】
  8. 多组radio传值注意事项
  9. jQuery中get与eq的区别
  10. Webdriver:Unsupported Marionette protocol version 2, required 3