Vue + Node.js + MongoDB圖片上傳元件實現圖片預覽和刪除功能詳解
本文例項講述了Vue + Node.js + MongoDB圖片上傳元件實現圖片預覽和刪除功能。分享給大家供大家參考,具體如下:
公司要寫一些為自身業務量身定製的的元件,要基於Vue,寫完後擴充套件了一下功能,選擇寫圖片上傳是因為自己之前一直對這個功能比較迷糊,所以這次好好了解了一下。演示在網址開啟後的show.gif中。
使用技術:Vue.js | node.js | express | MongoDB。
github網址:https://github.com/neroneroffy/private-project/tree/master/vue_uploader
功能
- 單圖多圖上傳
- 圖片上傳預覽
- 上傳進度條
- 分組上傳,分組查詢
- 新建分組,刪除分組
- 刪除圖片
- 選擇圖片
目錄結構
前端利用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].name); let fileReader = new FileReader(); //解析圖片路徑,實現預覽 fileReader.readAsDataURL(file.files[count]); fileReader.onload=()=>{ previewData = { url:fileReader.result,name:file.files[count].name,}; _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({},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'},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},data:queryResult.picList }) } }); } } }) } } }) }
最後,呼叫解析檔案函式
form.parse(req,fields,files)=>{ //傳多個檔案 if(files.file instanceof Array){ return }else{ //傳單個檔案 handleFile(files.file) } });
資料庫結構:
剩下的還有檔案刪除,新增分組,刪除分組,分組查詢的功能,由於篇幅有限,這些功能可以去看原始碼
第一次用node和mongoDB寫後臺業務,還有很多地方需要完善,程式碼會繼續更新~
希望本文所述對大家vue.js程式設計有所幫助。