您好,登錄后才能下訂單哦!
這篇文章主要講解了Vue + Node.js + MongoDB圖片上傳組件如何實(shí)現(xiàn)圖片預(yù)覽和刪除功能,內(nèi)容清晰明了,對(duì)此有興趣的小伙伴可以學(xué)習(xí)一下,相信大家閱讀完之后會(huì)有幫助。
公司要寫(xiě)一些為自身業(yè)務(wù)量身定制的的組件,要基于Vue,寫(xiě)完后擴(kuò)展了一下功能,選擇寫(xiě)圖片上傳是因?yàn)樽约褐耙恢睂?duì)這個(gè)功能比較迷糊,所以這次好好了解了一下。演示在網(wǎng)址打開(kāi)后的show.gif中。
使用技術(shù):Vue.js | node.js | express | MongoDB。
前端利用Vue搭建,Entry.vue中引入子組件Upload.vue。在Upload.vue中,使用input標(biāo)簽,上傳圖片,form表單提交數(shù)據(jù),但是from讓人很頭疼,提交后刷新頁(yè)面,所以給它綁定了一個(gè)隱藏的iframe標(biāo)簽來(lái)實(shí)現(xiàn)無(wú)刷新提交表單。
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" ></iframe>
調(diào)用上傳函數(shù)提交完數(shù)據(jù)后:
upload(); document.forms[0].target="rfFrame";
圖片預(yù)覽
利用html5的fileReader對(duì)象
let count = 0;//上傳函數(shù)外定義變量,記錄文件的數(shù)量,即遞歸的次數(shù) /*-----------------------此段代碼在上傳函數(shù)中-------------------------------*/ let fileReader = new FileReader(); //解析圖片路徑,實(shí)現(xiàn)預(yù)覽 fileReader.readAsDataURL(file.files[count]); fileReader.onload=()=>{ previewData = { url:fileReader.result,//圖片預(yù)覽的img標(biāo)簽的src name:file.files[count].name, size:file.files[count].size, }; //這段代碼在上傳函數(shù)中,所以在外面定義了一個(gè)_this = this,fileList為vue的data中定義的狀態(tài) _this.fileList.push(previewData); };
進(jìn)度條實(shí)現(xiàn)
在axios的配置中定義onUploadProgress函數(shù),接收參數(shù):progressEvent,利用它的兩個(gè)屬性:progressEvent.total和progressEvent.loaded(上傳的文件總字節(jié)數(shù)和已上傳的字節(jié)數(shù))
node寫(xiě)接口,實(shí)現(xiàn)圖片的接收、查詢、刪除。實(shí)現(xiàn)分組的新增、查詢、刪除。利用Formidable模塊接收并處理前端傳過(guò)來(lái)的表單數(shù)據(jù)。利用fs模塊實(shí)現(xiàn)刪除文件功能。
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);
對(duì)于上傳方式,我這里統(tǒng)一采用依次上傳,無(wú)論是單圖多圖,單圖上傳一次就好,多圖則遞歸調(diào)用上傳函數(shù),直到遞歸次數(shù)等于圖片數(shù)量,停止遞歸。
上傳函數(shù)
let file=$event.target, formData = new FormData(); //遞歸調(diào)用自身,實(shí)現(xiàn)多文件依次上傳 let _this = this; let count = 0; let previewData = {}; uploadImage($event){ let file=$event.target, formData = new FormData(); //遞歸調(diào)用自身,實(shí)現(xiàn)多文件依次上傳 let _this = this; let count = 0; let previewData = {}; function upload(){ //開(kāi)始上傳時(shí),滾到底部 _this.$refs.picWrapper.scrollTop = _this.$refs.picWrapper.scrollHeight; //定義axios配置信息 let progress = 0; let config = { headers: {'Content-Type': 'multipart/form-data'}, onUploadProgress (progressEvent){ console.log(`進(jìn)度條的數(shù)量${_this.$refs.progress.length -1}`); if(progressEvent.lengthComputable){ progress = progressEvent.total/progressEvent.loaded; //進(jìn)度條 _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(); //解析圖片路徑,實(shí)現(xiàn)預(yù)覽 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=()=>{ //檢測(cè)圖片大小是否超出限制 if(formData.get('file').size>_this.maxSize){ formData.delete('file'); //當(dāng)圖片全部上傳完畢,停止遞歸 count++; if(count > file.files.length-1){ return } upload() }else{ //發(fā)送數(shù)據(jù) 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{ //如果是選擇其他組上傳,直接把返回?cái)?shù)據(jù)賦值到文件數(shù)組 _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'); }); } }; } } //第一次調(diào)用 upload(); document.forms[0].target="rfFrame"; }
//引入表單處理模塊 let Formidable = require("formidable");
一系列定義....
form.encoding = 'utf-8'; form.uploadDir = '/project/vue/vue_uploader/my-server/public/images';//定義文件存放地址 form.keepExtensions = true; form.multiples = false;//以單文件依次上傳的方式,實(shí)現(xiàn)多文件上傳 form.maxFieldsSize = 1*1024; //解析圖片,重命名圖片名稱,返回給前端。 let fileData = ""; let fileDir = "images";//定義文件的存放路徑 let route = 'upload_';//定義路由 let serverIp = 'http://localhost:3002/';//定義服務(wù)器IP
對(duì)文件數(shù)據(jù)進(jìn)行處理,存入本地并存入數(shù)據(jù)庫(kù)(由于涉及到分組上傳。。。所以比較復(fù)雜)
解析文件函數(shù):
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:'發(fā)生錯(cuò)誤了' }) }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 }) } }); } } }) } } }) }
最后,調(diào)用解析文件函數(shù)
form.parse(req,(err,fields,files)=>{ //傳多個(gè)文件 if(files.file instanceof Array){ return }else{ //傳單個(gè)文件 handleFile(files.file) } });
數(shù)據(jù)庫(kù)結(jié)構(gòu):
剩下的還有文件刪除,新增分組,刪除分組,分組查詢的功能,由于篇幅有限,這些功能可以去看源碼
第一次用node和mongoDB寫(xiě)后臺(tái)業(yè)務(wù),還有很多地方需要完善,代碼會(huì)繼續(xù)更新~
看完上述內(nèi)容,是不是對(duì)Vue + Node.js + MongoDB圖片上傳組件如何實(shí)現(xiàn)圖片預(yù)覽和刪除功能有進(jìn)一步的了解,如果還想學(xué)習(xí)更多內(nèi)容,歡迎關(guān)注億速云行業(yè)資訊頻道。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。