1. 程式人生 > 程式設計 >Vue + Node.js + MongoDB圖片上傳元件實現圖片預覽和刪除功能詳解

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 + Node.js + MongoDB圖片上傳元件實現圖片預覽和刪除功能詳解

功能

  • 單圖多圖上傳
  • 圖片上傳預覽
  • 上傳進度條
  • 分組上傳,分組查詢
  • 新建分組,刪除分組
  • 刪除圖片
  • 選擇圖片

目錄結構

Vue + Node.js + MongoDB圖片上傳元件實現圖片預覽和刪除功能詳解

前端利用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)
  }
});

資料庫結構:

Vue + Node.js + MongoDB圖片上傳元件實現圖片預覽和刪除功能詳解

剩下的還有檔案刪除,新增分組,刪除分組,分組查詢的功能,由於篇幅有限,這些功能可以去看原始碼

第一次用node和mongoDB寫後臺業務,還有很多地方需要完善,程式碼會繼續更新~

希望本文所述對大家vue.js程式設計有所幫助。