公司需要写一些适合自己业务的组件。之所以上传图片,是因为之前对这个功能一直很迷茫,所以这次对它有了一个很好的理解。打开url后demo在show.gif中。使用的技术:Vue.js|节点.js|快递|MongoDB。githubURL:https://github.com/neroneroff...功能单图多图上传图片上传预览上传进度条群组上传,群组查询新建群组,删除群组删除图片选择图片目录结构前端搭建有Vue,入口。vue中引入了子组件Upload.vue。Upload.vue中使用input标签上传图片和form表单提交数据,但是from很头疼,而且提交后页面会刷新,所以给它绑定了一个隐藏的iframe标签实现无刷新提交形式。在Dom中:上传图片调用上传函数提交数据后:upload();document.forms[0].target="rfFrame";图片预览使用html5的fileReader对象letcount=0;//在上传函数外定义变量,记录文件个数,即递归次数/*------------------------这段代码在上传功能中------------------------------*/letfileReader=newFileReader();//解析图片的路径实现预览fileReader.readAsDataURL(file.files[count]);fileReader.onload=()=>{previewData={url:fileReader.result,//图片预览src的img标签name:file.files[count].name,size:file.files[count].size,};//这段代码是在上传函数里面,所以在外面定义了一个_this=this,fileList是vuedata_this.fileList.push中定义的state(预览数据);};进度条实现在axios配置中定义了onUploadProgress函数,接收参数:progressEvent,使用它的两个属性:progressEvent.total和progressEvent.loaded(上传文件总字节数和字数节点数)节点写入接口,实现图片的接收、查询、删除,实现分组的添加、查询、删除。使用Formidable模块接收和处理来自前端的表单数据。使用fs模块实现删除文件的功能。letprogress=0;letconfig={headers:{'Content-Type':'multipart/form-data'},onUploadProgress(progressEvent){if(progressEvent.lengthComputable){progress=progressEvent.total/progressEvent.loaded;_this.$refs.progress[_this.$refs.progress.length-1].style.width=Number(progress).toFixed(2)*100+"%";}}};将文件插入formDataformData=newFormData();if(file.files[count]){formData.append('file',file.files[count],file.files[count].name);上传方式,我这里按顺序上传。不管是单图多图,单图上传一次就够了。对于多张图片,会递归调用上传函数,直到递归次数等于图片数量,递归停止。上传函数letfile=$event.target,formData=newFormData();//递归调用自身依次上传多个文件let_this=this;让计数=0;让previewData={};uploadImage($event){letfile=$event.target,formData=newFormData();//递归调用自身将多个文件一个一个上传let_this=this;让计数=0;让previewData={};functionupload(){//开始上传时,滚动到底部_this.$refs.picWrapper.scrollTop=_this.$refs.picWrapper.scrollHeight;//定义axios配置信息letprogress=0;letconfig={headers:{'Content-Type':'multipart/form-data'},onUploadProgress(progressEvent){console.log(`进度条数${_this.$refs.progress.length-1}`);如果(progressEvent.lengthComputable){progress=progressEvent.total/progressEvent.loaded;//进度条_this.$refs.progress[_this.$refs.progress.length-1].style.width=Number(progress).toFixed(2)*100+"%";}}};//将文件插入formDataif(file.files[count]){formData.append('file',file.files[count],file.files[count].name);让fileReader=newFileReader();//解析图片的路径实现预览fileReader.readAsDataURL(file.files[count]);fileReader.onload=()=>{previewData={url:fileReader.result,name:file.files[count].名称,大小:file.files[count].size,};_this.fileList.push(预览数据);_this.progressShow=true};fileReader.onloadend=()=>{//检测图片大小是否超过限制if(formData.get('file').size>_this.maxSize){formData.delete('file');//当所有图片上传完毕,停止递归计数++;if(count>file.files.length-1){return}upload()}else{//发送数据axios.post(`/upload?mark=${_this.group}`,formData,config).then((回复)=>{formData.delete('文件');让res=response.data;控制台日志(资源);if(res.result){//如果是新上传if(_this.group==='new'){_this.fileList.push(res.data);_this.fileList.forEach((item,index)=>{if(!item.newName){_this.fileList.splice(index,1)}})}else{//如果选择其他组上传,直接赋值返回数据到文件数组_this.fileList=res.data;}_this.newUpload=false}else{alert('上传失败');返回;}_this.noPic=false;计数++;if(count>file.files.length-1){return}upload()}).catch((err)=>{alert('上传失败123');});}};}}//第一次调用upload();document.forms[0].target="rfFrame";}node.jswritebackend//引入表单处理模块letFormidable=require("formidable");一系列定义....form.encoding='utf-8';form.uploadDir='/project/vue/vue_uploader/my-server/public/images';//定义文件存放地址form.keepExtensions=true;form.multiples=false;//使用单文件顺序上传,实现多文件上传form.maxFieldsSize=1*1024;//解析图片,重命名图片名称,返回给前端letfileData="";letfileDir="images";//定义文件的存放路径letroute='upload_';//定义路由letserverIp='http://localhost:3002/';//定义服务器IP对文件数据进行处理,存储到本地,存入数据库(因为涉及到组上传...所以比较复杂)解析文件函数:functionhandleFile(file){letfilename=file.name;让nameArray=filename.split('.');lettype=nameArray[nameArray.length-1];让名字='';for(leti=0;i{if(err){res.json({result:false,msg:err.message})}else{if(doc){doc.picList.push(fileData);doc.save((err,saveResult)=>{if(err){returnres.json({result:false,});}else{letlength=doc.picList.length;console.log(doc.picList.length)if(groupMark==='all'){UploadData.find({},(err,queryResult)=>{if(err){res.json({result:false,mgs:'发生错误了'})}else{让allPic=[];queryResult.forEach((item)=>{if(item.group!=='default'){allPic=allPic.concat(item.picList)}});res.json({result:true,data:allPic.concat(queryResult[1].picList)})}})}elseif(groupMark==='new'){UploadData.findOne({group:'default'},(err,queryResult)=>{if(err){returnres.json({结果:false,msg:err.message});}else{returnres.json({result:true,data:queryResult.picList[queryResult.picList.length-1]})}});}else{UploadData.findOne({group:group},(err,queryResult)=>{if(err){returnres.json({result:false,msg:err.message});}else{returnres.json({结果:true,数据:queryResult.picList})}});}}})}}})}最后调用解析文件函数form.parse(req,(err,fields,files)=>{//传递多个文件if(files.fileinstanceofArray){return}else{//发送单个文件handleFile(files.file)}});数据库结构:其余功能包括文件删除、新建分组、删除分组、分组查询。由于篇幅有限,可以去掉这些功能查看源码,第一次使用node和mongoDB写后台业务。还有很多需要改进的地方,代码会持续更新~