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和PHP实现类似360功能开关效果
Feb 12 Javascript
JavaScript中标识符提升问题
Jun 11 Javascript
JS实现table表格数据排序功能(可支持动态数据+分页效果)
May 26 Javascript
vue日期组件 支持vue1.0和2.0
Jan 09 Javascript
在js代码拼接dom对象到页面上去的模板总结(必看)
Feb 14 Javascript
基于JavaScript定位当前的地理位置
Apr 11 Javascript
JS库之wow.js使用方法
Sep 14 Javascript
vue addRoutes实现动态权限路由菜单的示例
May 15 Javascript
vue.js使用3DES加密的方法示例
May 18 Javascript
webpack file-loader和url-loader的区别
Jan 15 Javascript
layui使用button按钮 点击出现弹层 弹层中加载表单的实例
Sep 04 Javascript
Vue路由管理器Vue-router的使用方法详解
Feb 05 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
用libTemplate实现静态网页的生成
2006/10/09 PHP
BBS(php &amp; mysql)完整版(四)
2006/10/09 PHP
PHP curl_setopt()函数实例代码与参数分析
2011/06/02 PHP
关于php内存不够用的快速解决方法
2013/10/26 PHP
2017年最新PHP经典面试题目汇总(上篇)
2017/03/17 PHP
PHP基于SimpleXML生成和解析xml的方法示例
2017/07/17 PHP
短信提示使用 特效
2007/01/19 Javascript
使用js完成节点的增删改复制等的操作
2014/01/02 Javascript
jQuery中before()方法用法实例
2014/12/25 Javascript
详解AngularJS Filter(过滤器)用法
2015/12/28 Javascript
在React框架中实现一些AngularJS中ng指令的例子
2016/03/06 Javascript
微信小程序ajax实现请求服务器数据及模版遍历数据功能示例
2017/12/15 Javascript
jQuery实现购物车的总价计算和总价传值功能
2018/11/28 jQuery
javascript设计模式 ? 工厂模式原理与应用实例分析
2020/04/09 Javascript
vue实现防抖的实例代码
2021/01/11 Vue.js
python常用web框架简单性能测试结果分享(包含django、flask、bottle、tornado)
2014/08/25 Python
Python解决鸡兔同笼问题的方法
2014/12/20 Python
Python实现针对含中文字符串的截取功能示例
2017/09/22 Python
Python使用Selenium+BeautifulSoup爬取淘宝搜索页
2018/02/24 Python
Python获取航线信息并且制作成图的讲解
2019/01/03 Python
python DataFrame转dict字典过程详解
2019/12/26 Python
Pycharm最常用的快捷键及使用技巧
2020/03/05 Python
Python 解决火狐浏览器不弹出下载框直接下载的问题
2020/03/09 Python
python新式类和经典类的区别实例分析
2020/03/23 Python
Python正则re模块使用步骤及原理解析
2020/08/18 Python
python自动从arxiv下载paper的示例代码
2020/12/05 Python
Django权限控制的使用
2021/01/07 Python
static全局变量与普通的全局变量有什么区别?static局部变量和普通局部变量有什么区别?static函数与普通函数有什么区别?
2015/02/22 面试题
旅游管理专业个人求职信范文
2013/12/24 职场文书
房产委托公证书
2014/04/08 职场文书
招股说明书范本
2014/05/06 职场文书
机修车间主任岗位职责
2015/04/08 职场文书
2015年建筑工程工作总结
2015/05/13 职场文书
追讨欠款律师函
2015/05/27 职场文书
初中体育教学随笔
2015/08/15 职场文书
如何用python识别滑块验证码中的缺口
2021/04/01 Python