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


Posted in Javascript onApril 29, 2020

本文实例讲述了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程序设计有所帮助。

Javascript 相关文章推荐
jquery实现保存已选用户
Jul 21 Javascript
jQuery操作cookie方法实例教程
Nov 25 Javascript
jQuery中animate()方法用法实例
Dec 24 Javascript
js实现全国省份城市级联下拉菜单效果代码
Sep 07 Javascript
基于JavaScript实现类似于百度学术高级检索功能
Mar 02 Javascript
jQuery实现背景弹性滚动的导航效果
Jun 01 Javascript
node.js的事件机制
Feb 08 Javascript
vue-cli单页应用改成多页应用配置详解
Jul 14 Javascript
Vue.js弹出模态框组件开发的示例代码
Jul 26 Javascript
微信小程序如何加载数据库真实数据的实现
Mar 04 Javascript
JS实现密码框效果
Sep 10 Javascript
几款主流好用的富文本编辑器(所见即所得常用编辑器)介绍
Mar 17 Javascript
JS数组push、unshift、pop、shift方法的实现与使用方法示例
Apr 29 #Javascript
JS实现手写 forEach算法示例
Apr 29 #Javascript
Node.js API详解之 querystring用法实例分析
Apr 29 #Javascript
Node.js API详解之 string_decoder用法实例分析
Apr 29 #Javascript
深入浅析vue全局环境变量和模式
Apr 28 #Javascript
你准备好迎接vue3.0了吗
Apr 28 #Javascript
JavaScript禁止右击保存图片,禁止拖拽图片的实现代码
Apr 28 #Javascript
You might like
PHP与已存在的Java应用程序集成
2006/10/09 PHP
php去除html标记的原生函数详解
2015/01/27 PHP
Laravel 5框架学习之用户认证
2015/04/09 PHP
php邮箱地址正则表达式验证
2015/11/13 PHP
PHP线程的内存回收问题
2016/07/08 PHP
iOS自定义提示弹出框实现类似UIAlertView的效果
2016/11/16 PHP
Laravel使用swoole实现websocket主动消息推送的方法介绍
2019/10/20 PHP
实现复选框全选/全不选切换
2006/12/23 Javascript
javascript instanceof 与typeof使用说明
2010/01/11 Javascript
Javascript 键盘事件的组合使用实现代码
2012/05/04 Javascript
jQuery晃动层特效实现方法
2015/03/09 Javascript
js完美解决IE6不支持position:fixed的bug
2015/04/24 Javascript
javascript实现的图片切割多块效果实例
2015/05/07 Javascript
5个最顶级jQuery图表类库插件【jquery插件库】
2016/05/05 Javascript
最全的Javascript编码规范(推荐)
2016/06/22 Javascript
Bootstrap table的使用方法
2016/11/02 Javascript
JavaScript链式调用原理与实现方法详解
2020/05/16 Javascript
Python的Bottle框架中实现最基本的get和post的方法的教程
2015/04/30 Python
Python聚类算法之凝聚层次聚类实例分析
2015/11/20 Python
Python基于list的append和pop方法实现堆栈与队列功能示例
2017/07/24 Python
python 识别图片中的文字信息方法
2018/05/10 Python
win7+Python3.5下scrapy的安装方法
2018/07/31 Python
Python从入门到精通之环境搭建教程图解
2019/09/26 Python
Python Pandas 转换unix时间戳方式
2019/12/07 Python
Python面向对象之继承原理与用法案例分析
2019/12/31 Python
基于python求两个列表的并集.交集.差集
2020/02/10 Python
Python装饰器实现方法及应用场景详解
2020/03/26 Python
python如何提升爬虫效率
2020/09/27 Python
python的setattr函数实例用法
2020/12/16 Python
表单button的outline在firefox浏览器下的问题
2012/12/24 HTML / CSS
荷兰多品牌网上鞋店:Stoute Schoenen
2017/08/24 全球购物
2014植树节活动总结
2014/03/11 职场文书
学生上课看漫画的检讨书
2014/09/26 职场文书
2014年节能减排工作总结
2014/12/06 职场文书
优秀大学生事迹材料
2014/12/24 职场文书
入党转正申请自我鉴定
2019/06/25 职场文书