Vue + Node.js + MongoDB图片上传组件实现图片预览和删除功能详解

作者:nero 时间:2024-05-10 14:14:56 

本文实例讲述了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],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)
 }
});

数据库结构:

Vue + Node.js + MongoDB图片上传组件实现图片预览和删除功能详解

剩下的还有文件删除,新增分组,删除分组,分组查询的功能,由于篇幅有限,这些功能可以去看源码

第一次用node和mongoDB写后台业务,还有很多地方需要完善,代码会继续更新~

希望本文所述对大家vue.js程序设计有所帮助。

来源:https://segmentfault.com/a/1190000012349559

标签:Vue,Node.js,MongoDB,图片预览
0
投稿

猜你喜欢

  • sqlserver2005 xml字段的读写操作

    2024-01-16 23:00:37
  • python实战之德州扑克第三步-比较大小

    2022-01-01 22:27:11
  • 设计上的小细节

    2010-06-24 21:44:00
  • 如何合理使用数据库冗余字段的方法

    2024-01-18 16:52:00
  • 将mysql转换到oracle必须了解的50件事

    2010-07-05 12:15:00
  • Vue开发工具之vuejs-devtools安装教程及常见问题解决(最详细)

    2024-05-10 14:09:33
  • ZABBIX3.2使用python脚本实现监控报表的方法

    2021-04-11 20:15:02
  • 正则表达式验证IPV4地址功能实例分析

    2023-06-13 13:11:05
  • python之线程池map()方法传递多参数list

    2022-06-13 09:00:55
  • sql将一个表中的数据插入到另一个表中的方法

    2024-01-27 22:30:20
  • 详解如何使用Python网络爬虫获取招聘信息

    2021-09-28 06:58:17
  • python 上下文管理器及自定义原理解析

    2023-01-24 20:07:55
  • Go 中的空白标识符下划线

    2024-04-29 13:04:42
  • python DataFrame 取差集实例

    2021-06-06 01:22:24
  • Jenkins配置maven项目之打包、部署、发布的全过程

    2023-08-07 19:14:29
  • MySQL数据库约束操作示例讲解

    2024-01-13 23:47:58
  • pytorch 如何使用amp进行混合精度训练

    2023-12-25 13:35:02
  • python中main函数(主函数)相关应用例子

    2023-08-23 08:54:59
  • Python实现印章代码的算法解析

    2023-10-14 15:18:24
  • Oracle RMAN快速入门指南

    2010-07-18 12:50:00
  • asp之家 网络编程 m.aspxhome.com