Vue + Node.js + MongoDB图片上传组件实现图片预览和删除功能详解
本文实例讲述了vue + node.js + mongodb图片上传组件实现图片预览和删除功能。分享给大家供大家参考,具体如下:
公司要写一些为自身业务量身定制的的组件,要基于vue,写完后扩展了一下功能,选择写图片上传是因为自己之前一直对这个功能比较迷糊,所以这次好好了解了一下。演示在网址打开后的show.gif中。
使用技术:vue.js | node.js | express | mongodb。
github网址:
功能
- 单图多图上传
- 图片上传预览
- 上传进度条
- 分组上传,分组查询
- 新建分组,删除分组
- 删除图片
- 选择图片
目录结构
前端利用vue搭建,entry.vue中引入子组件upload.vue。在upload.vue中,使用input标签,上传图片,form表单提交数据,但是from让人很头疼,提交后刷新页面,所以给它绑定了一个隐藏的iframe标签来实现无刷新提交表单。
dom中:
<form class="upload-content-right-top" enctype="multipart/form-data" ref="formsubmit" > <label class="upload-content-right-top-btn">上传图片</label> <input type="file" @change="uploadimage($event)" multiple="multiple" accept="image/gif, image/jpeg, image/png"> </form> <iframe id="rfframe" name="rfframe" src="about:blank" style="display:none;"></iframe>
调用上传函数提交完数据后:
upload(); document.forms[0].target="rfframe";
图片预览
利用html5的filereader对象
let count = 0;//上传函数外定义变量,记录文件的数量,即递归的次数 /*-----------------------此段代码在上传函数中-------------------------------*/ let filereader = new filereader(); //解析图片路径,实现预览 filereader.readasdataurl(file.files[count]); filereader.onload=()=>{ previewdata = { url:filereader.result,//图片预览的img标签的src name:file.files[count].name, size:file.files[count].size, }; //这段代码在上传函数中,所以在外面定义了一个_this = this,filelist为vue的data中定义的状态 _this.filelist.push(previewdata); };
进度条实现
在axios的配置中定义onuploadprogress函数,接收参数:progressevent,利用它的两个属性:progressevent.total和progressevent.loaded(上传的文件总字节数和已上传的字节数)
node写接口,实现图片的接收、查询、删除。实现分组的新增、查询、删除。利用formidable模块接收并处理前端传过来的表单数据。利用fs模块实现删除文件功能。
let progress = 0; let config = { 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+"%"; } } };
向formdata中插入文件
formdata = new formdata(); if(file.files[count]){ formdata.append('file',file.files[count],file.files[count].name);
对于上传方式,我这里统一采用依次上传,无论是单图多图,单图上传一次就好,多图则递归调用上传函数,直到递归次数等于图片数量,停止递归。
上传函数
let file=$event.target, formdata = new formdata(); //递归调用自身,实现多文件依次上传 let _this = this; let count = 0; let previewdata = {}; uploadimage($event){ let file=$event.target, formdata = new formdata(); //递归调用自身,实现多文件依次上传 let _this = this; let count = 0; let previewdata = {}; function upload(){ //开始上传时,滚到底部 _this.$refs.picwrapper.scrolltop = _this.$refs.picwrapper.scrollheight; //定义axios配置信息 let progress = 0; let config = { headers: {'content-type': 'multipart/form-data'}, onuploadprogress (progressevent){ console.log(`进度条的数量${_this.$refs.progress.length -1}`); if(progressevent.lengthcomputable){ progress = progressevent.total/progressevent.loaded; //进度条 _this.$refs.progress[_this.$refs.progress.length-1].style.width = number(progress).tofixed(2)*100+"%"; } } }; //向formdata中插入文件 if(file.files[count]){ formdata.append('file',file.files[count],file.files[count].name); let filereader = new filereader(); //解析图片路径,实现预览 filereader.readasdataurl(file.files[count]); filereader.onload=()=>{ previewdata = { url:filereader.result, name:file.files[count].name, size:file.files[count].size, }; _this.filelist.push(previewdata); _this.progressshow = true }; filereader.onloadend=()=>{ //检测图片大小是否超出限制 if(formdata.get('file').size>_this.maxsize){ formdata.delete('file'); //当图片全部上传完毕,停止递归 count++; if(count > file.files.length-1){ return } upload() }else{ //发送数据 axios.post(`/upload?mark=${_this.group}`,formdata,config).then((response)=>{ formdata.delete('file'); let res = response.data; console.log(res); 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('上传失败'); return; } _this.nopic = false; count++; if(count > file.files.length-1){ return } upload() }).catch((err)=>{ alert('上传失败123'); }); } }; } } //第一次调用 upload(); document.forms[0].target="rfframe"; }
node.js写后端
//引入表单处理模块 let formidable = 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; //解析图片,重命名图片名称,返回给前端。 let filedata = ""; let filedir = "images";//定义文件的存放路径 let route = 'upload_';//定义路由 let serverip = 'http://localhost:3002/';//定义服务器ip
对文件数据进行处理,存入本地并存入数据库(由于涉及到分组上传。。。所以比较复杂)
解析文件函数:
function handlefile (file){ let filename = file.name; let namearray = filename.split('.'); let type = namearray[namearray.length-1]; let name = ''; for (let i = 0;i<namearray.length - 1;i++){ name = name + namearray[i]; } let date = new date(); let time = '_' + date.getfullyear() + "_" + date.getmonth() + "_" + date.getday() + "_" + date.gethours() + "_" + date.getminutes() +"_"+ date.getseconds()+"_"+date.getmilliseconds(); let picname = name + time + '.' + type; let newpath = form.uploaddir + "/" + picname; let oldpath = form.uploaddir + "/"+ file.path.substring(file.path.indexof(route)); fs.renamesync(oldpath, newpath); //重命名 filedata = { id:`${new date().gettime()}`, url:serverip + newpath.substring(newpath.indexof(filedir)), name:file.name, size:file.size, isselected:false, newname:picname, }; uploaddata.findone({group:group},(err,doc)=>{ if(err){ res.json({ result:false, msg:err.message }) }else{ if(doc){ doc.piclist.push(filedata); doc.save((err,saveresult)=>{ if(err){ return res.json({ result:false, }); }else{ let length= doc.piclist.length; console.log(doc.piclist.length) if(groupmark === 'all'){ uploaddata.find({},(err,queryresult)=>{ if(err){ res.json({ result:false, mgs:'发生错误了' }) }else{ let allpic = []; queryresult.foreach((item)=>{ if(item.group !=='default'){ allpic = allpic.concat(item.piclist) } }); res.json({ result:true, data:allpic.concat(queryresult[1].piclist) }) } }) }else if(groupmark === 'new'){ uploaddata.findone({group:'default'},(err,queryresult)=>{ if(err){ return res.json({ result:false, msg:err.message }); }else{ return res.json({ result:true, data:queryresult.piclist[queryresult.piclist.length-1] }) } }); }else{ uploaddata.findone({group:group},(err,queryresult)=>{ if(err){ return res.json({ result:false, msg:err.message }); }else{ return res.json({ result:true, data:queryresult.piclist }) } }); } } }) } } }) }
最后,调用解析文件函数
form.parse(req,(err,fields,files)=>{ //传多个文件 if(files.file instanceof array){ return }else{ //传单个文件 handlefile(files.file) } });
数据库结构:
剩下的还有文件删除,新增分组,删除分组,分组查询的功能,由于篇幅有限,这些功能可以去
第一次用node和mongodb写后台业务,还有很多地方需要完善,代码会继续更新~
希望本文所述对大家vue.js程序设计有所帮助。