在这次博客中我们为用户增加头像
实现功能
- 用户头像上传
- 为每个用户提供三个候选头像,分别是最近两次的头像和系统默认头像
依赖的第三方工具
- AngularJS前端框架
- Express后端框架
- Angular-File-upload插件
- connect-busboy插件
- then.js小工具
- mongoose数据库插件
问题分析
用一个长度为3的栈来保存用户的候选头像,且栈的底部必定是系统默认头像,越新的头像就越靠近栈顶
情况分类
上传新头像
用户上传与之前上传过的同名头像怎么办?
- 与当前头像名相同,什么都不做
- 与备用头像名相同,当前头像入栈,删除备用头像名,当前改为上传头像名
- 都不相同,当前头像入栈,再看长度有没有超,超了删第一号头像(默认后面的那个)
在备用头像里更换
- 用户选择默认头像,当前也是默认,不做任何事
- 用户选备用头像,当前是默认头像,当前头像不入栈,栈删除对应备用头像
- 用户选默认头像,当前头像非默认,当前头像入栈,若栈长超过3,删除1号头像
- 当前非默认头像,用户选备用头像,当前头像入栈,删除相应备用头像
页面代码
由于在我的博客中前端实战之用户控制台中有详细的页面代码这里只出示一小部分,方便大家阅读
<label class="control-label col-sm-2">
头像
</label>
<div class="avatar col-sm-2">
<img alt="用户头像" class="img-circle" ng-src="{{profile.avatar}}">
</div>
<div class="btn-group change-avatar col-sm-2">
<button class="btn btn-default dropdown-toggle" data-toggle="dropdown">
更换头像
<span class="caret"></span>
</button>
<ul class="dropdown-menu" role="menu">
<li class="upload-button">
<div class="btn btn-lg btn-link upload-avatar" type="file" ng-file-select="fileSelect($files)" accept="image/*">
<span class="glyphicon glyphicon-pencil"></span>
上传头像
</div>
</li>
<li class="divider">
</li>
<li class="available-avatar">
<img ng-repeat="pic in picList" ng-src="{{pic}}" ng-click="changeAvatar(pic)">
</li>
</ul>
</div>
前端代码
angular.module('settingAPP',['myApp.Services','angularFileUpload']).controller('profileCtrl',function($rootScope,$scope,$http,$upload){
$scope.count=0;
$scope.$on('userDone',function(){
$scope.profile=document.user.profile;
$scope.picList=$scope.profile.available_avatar;
});
$scope.fileSelect=function($files){
var file=$files[0];
$scope.upload=$upload.upload({
url:'/settings/newAvatar',
file:file
}).success(function(data, status, headers, config){
if(!data.success){
if(!data.err.message) data.err.message="未知错误,稍后再试"
$rootScope.msg=data.err.message;
$rootScope.display=true;
}
else{
$scope.profile.avatar=data.avatar_path;
$scope.picList=data.list;
}
});
};
$scope.changeAvatar=function(pic){
var count,tmp;
for(var i=0;i<3;i++){
if($scope.picList[i]==pic){
count=i;
}
}
$http.post('/settings/changeAvatar',{pic:pic,num:count}).success(function(data){
if(!data.success){
if(!data.err.message) data.err.message="未知错误,稍后再试"
$rootScope.msg=data.err.message;
$rootScope.display=true;
}
else{
$scope.picList=data.list;
$scope.profile.avatar=pic;
}
}).error(function(data){
$rootScope.msg='未知错误,请重试';
$rootScope.display=true;
});
};
});
后端代码
function newAvatar(req,res){//上传新头像
var img_path;
Then(function(cont){
req.pipe(req.busboy);
req.busboy.on('file',cont);
}).fin(function(cont,fieldname,file,filename){
img_path='/img/avatar/'+req.session.uname+'_'+filename;
var fileStream=fs.createWriteStream('public'+img_path);
file.pipe(fileStream);
fileStream.on('close',cont);
}).fin(function(cont){
User.findOne({username:req.session.uname},cont);
}).then(function(cont,doc){
if(!doc) return cont(new Err(msg.USER.userNone));
var tmp=doc.profile.available_avatar;
//与当前头像名相同,什么都不做
if(img_path==doc.profile.avatar) return cont(null,doc);
//与备用头像名相同,当前头像入栈,删除备用头像名,当前改为上传头像名
for(var i in tmp){
if(tmp[i]==img_path){
tmp.splice(i,1);
tmp.push(doc.profile.avatar);
doc.profile.avatar=img_path;
return doc.save(cont);
}
}
//都不相同,当前入栈,再看长度有没有超,超了删1号
tmp.push(doc.profile.avatar);
doc.profile.avatar=img_path;
if(tmp.length>3) tmp.splice(1,1);
return doc.save(cont);
}).then(function(cont,doc){
res.json({
success:true,
err:null,
avatar_path:img_path,
list:doc.profile.available_avatar
});
}).fail(EndHandler);
}
function changeAvatar(req,res){//从候选头像中选择
var tmp=req.body;
Then(function(cont){
User.findOne({username:req.session.uname},cont);
}).then(function(cont,doc){
if(!doc) return cont(new Err(msg.USER.userNone));
//与当前头像名相同,什么都不做
if(tmp.pic==doc.profile.avatar) return cont(null,doc);
//用户选默认,当前入栈,若栈长超过3,删除1号
if(tmp.num==0){
doc.profile.available_avatar.push(doc.profile.avatar);
if(doc.profile.available_avatar.length>3){
doc.profile.available_avatar.splice(1,1);
}
doc.profile.avatar=tmp.pic;
return doc.save(cont);
}
//用户选备用,当前默认,不入栈,删除对应备用
if(doc.profile.avatar==doc.profile.available_avatar[0]){
doc.profile.avatar=tmp.pic;
doc.profile.available_avatar.splice(tmp.num,1);
return doc.save(cont);
}
//当前非默认,用户选备用,当前入栈,删除相应备用
doc.profile.available_avatar.push(doc.profile.avatar);
doc.profile.available_avatar.splice(tmp.num,1);
doc.profile.avatar=tmp.pic;
return doc.save(cont);
}).then(function(cont,doc){
res.json({
success:true,
err:null,
list:doc.profile.available_avatar
});
}).fail(EndHandler);
}