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 相关文章推荐
IE中createElement需要注意的一个问题
Jul 13 Javascript
鼠标焦点离开文本框时验证的js代码
Jul 19 Javascript
JS实现简单的顶部定时关闭层效果
Jun 15 Javascript
javascript学习笔记(三)BOM和DOM详解
Sep 30 Javascript
javascript实现uploadify上传格式以及个数限制
Nov 23 Javascript
通用javascript代码判断版本号是否在版本范围之间
Nov 29 Javascript
JS+Canvas 实现下雨下雪效果
May 18 Javascript
微信小程序自定义多选事件的实现代码
May 17 Javascript
node.js实现微信开发之获取用户授权
Mar 18 Javascript
用node撸一个监测复联4开售短信提醒的实现代码
Apr 10 Javascript
Windows上node.js的多版本管理工具用法实例分析
Nov 06 Javascript
JS实现前端动态分页码代码实例
Jun 02 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
解决dede生成静态页和动态页转换的一些问题,及火车采集入库生成动态的办法
2007/03/29 PHP
中英文字符串翻转函数
2008/12/09 PHP
php不用内置函数对数组排序的两个算法代码
2010/02/08 PHP
php生成验证码函数
2015/10/20 PHP
Joomla数据库操作之JFactory::getDBO用法
2016/05/05 PHP
PHP获取日期对应星期、一周日期、星期开始与结束日期的方法
2018/06/22 PHP
jquery 打开窗口返回值实现代码
2010/03/04 Javascript
IE本地存储userdata的一个bug说明
2010/07/01 Javascript
javascript客户端解决方案 缓存提供程序
2010/07/14 Javascript
javascript实现跳转菜单的具体方法
2013/07/05 Javascript
JavaScript中为什么null==0为false而null大于=0为true(个人研究)
2013/09/16 Javascript
javascript抖动元素的小例子
2013/10/28 Javascript
JS图片切换的具体方法(带缩略图版)
2013/11/12 Javascript
jQuery获取URL请求参数的方法
2015/07/18 Javascript
JS实现鼠标滑过链接改变网页背景颜色的方法
2015/10/20 Javascript
Jquery技巧(必须掌握)
2016/03/16 Javascript
JavaScript简单实现合并两个Json对象的方法示例
2017/10/16 Javascript
浅谈vue-cli加载不到dev-server.js的解决办法
2017/11/24 Javascript
微信小程序实现下拉刷新动画
2019/06/21 Javascript
node.js使用mongoose操作数据库实现购物车的增、删、改、查功能示例
2019/12/23 Javascript
修改vue源码实现动态路由缓存的方法
2020/01/21 Javascript
微信小程序自定义tabBar的踩坑实践记录
2020/11/06 Javascript
三剑客:offset、client和scroll还傻傻分不清?
2020/12/04 Javascript
[59:48]DOTA2-DPC中国联赛 正赛 VG vs Magma BO3 第一场 1月26日
2021/03/11 DOTA
解决pycharm 误删掉项目文件的处理方法
2018/10/22 Python
pyqt5实现按钮添加背景图片以及背景图片的切换方法
2019/06/13 Python
python opencv 读取图片 返回图片某像素点的b,g,r值的实现方法
2019/07/03 Python
python读取Kafka实例
2019/12/23 Python
CSS3区域模块region相关编写示例
2015/08/28 HTML / CSS
利用HTML5实现使用按钮控制背景音乐开关
2015/09/21 HTML / CSS
韩国邮政旗下生鲜食品网上超市:epost
2016/08/27 全球购物
亚历山大·王官网:Alexander Wang
2017/06/23 全球购物
女孩每月服装订阅盒:kidpik
2019/04/17 全球购物
材料工程专业毕业生求职信
2014/03/04 职场文书
2014年保卫工作总结
2014/12/05 职场文书
css3 实现文字闪烁效果的三种方式示例代码
2021/04/25 HTML / CSS