node.js实现带进度条的多文件上传


Posted in Javascript onMarch 27, 2020

用node.js实现多文件上传并携带进度条的demo,供大家参考,具体内容如下

这个独立封装的需求来自一个朋友公司,他说需要写一个带进度条动画的批量上传文件的组件,结果他们后端跟他说不能多文件上传,我一听就很尴尬了,怎么可能不能多文件呢哈哈,后来我只是告诉他进度条的实现方式,在过了2天后我一直对此事耿耿于怀,所以干脆自己动手用node写了一个多文件上传的demo,并记录下来。

  • 前端: http请求为自己封装的一个原生请求函数,一切以原生代码为主;
  • 后端(nodeJs): express + multer,自定义 multer 包的 diskStorage 函数;

直接上demo吧,我加上一点注解就好,就不用详细说明了, 其中写了一个测试接口用来测试,可以不用管;

// 前端 upload.html
<!DOCTYPE html>
<html>
 <head>
 <meta charset="utf-8">
 <title>上传文件demo</title>
 <style media="screen">
  .progress{
  width: 50%;
  height: 5px;
  border: 1px solid #ccc;
  border-radius: 4px;
  margin-top: 10px;
  position: relative;
  }
  .progress>span{
  display: inline-block;
  position: absolute;
  border-radius: 4px;
  top: 0;
  left: 0;
  height: 100%;
  width: 0;
  background-color: rgb(98, 230, 74);
  transition: width 0.3s ease-out;
  }
 </style>
 </head>
 <body>
 <input id="file" type="file" multiple>
 <div class="progress">
  <span></span>
 </div>
 <script type="text/javascript">
  var http = function (option) {
  // 过滤请求成功后的响应对象
  function getBody (xhr) {
   var text = xhr.responseText || xhr.response
   if (!text) {
   return text
   }

   try {
   return JSON.parse(text)
   } catch (err) {
   return text
   }
  }

  var xhr = new XMLHttpRequest();
  // 自定义 beforeSend 函数
  if(option.beforeSend instanceof Function) {
   if (option.beforeSend(xhr) === false) {
   return false
   }
  }

  xhr.onreadystatechange = function () {
   if (xhr.status === 200) {
   if (xhr.readyState === 4) {
    // 成功回调
    option.onSuccess(getBody(xhr))
   }
   }
  }

  // 请求失败
  xhr.onerror = function (err) {
   option.onError(err)
  }

  xhr.open(option.type, option.url, true)

  // 当请求为上传文件时回调上传进度
  if (xhr.upload) {
   xhr.upload.onprogress = function (event) {
   if (event.total > 0) {
    event.percent = event.loaded / event.total * 100;
   }
   // 监控上传进度回调
   if (option.onProgress instanceof Function) {
    option.onProgress(event)
   }
   }
  }

  // 自定义头部
  const headers = option.headers || {}
  for (var item in headers) {
   xhr.setRequestHeader(item, headers[item])
  }

  xhr.send(option.data)
  }
 
 // 测试接口
  http({
  type: 'POST',
  url: '/test',
  data: JSON.stringify({
   name: 'yolo'
  }),
  onSuccess: function (data) {
   console.log(data)
  },
  onError: function (err) {
   console.log(err)
  }
  })
  document.getElementById('file').onchange = function () {
  var fileList = this.files, formData = new FormData();
  Array.prototype.forEach.call(fileList, function (file) {
   formData.append(file.name, file)
  })
  // 当上传的数据为 file 类型时,请求的格式类型自动会变为 multipart/form-data, 如果头部格式有特定需求,在我的 http 函数中传入 headers<Object> 即可,大家可自己查看,我这里没有什么特殊处理所以就不传了
  http({
   type: 'POST',
   url: '/upload',
   data: formData,
   onProgress: function (event) {
   console.log(event.percent)
   document.querySelector('.progress span').style.width = event.percent + '%';
   },
   onSuccess: function (data) {
   console.log('上传成功')
   },
   onError: function (err) {
   alert(err)
   }
  })
  }
 </script>
 </body>
</html>

后端所用的一些东西我放在这

express中间件-multer
express 4.x 文档

// 后端(node.js) upload.js
var express = require('express');
var path = require('path');
var fs = require('fs');
var app = express();
var bodyParser = require('body-parser'); // 过滤请求头部相应格式的body
var multer = require('multer');
var chalk = require('chalk'); // 只是一个 cli 界面字体颜色包而已
var log = console.log.bind(console);

app.use(express.static('static'));
// 接受 application/json 格式的过滤器
var jsonParser = bodyParser.json()
// 接受 application/x-www-form-urlencoded 格式的过滤器
var urlencodedParser = bodyParser.urlencoded({ extended: false })
// 接受 text/html 格式的过滤器
var textParser = bodyParser.text()

// 自定义 multer 的 diskStorage 的存储目录与文件名
var storage = multer.diskStorage({
 destination: function (req, file, cb) {
 cb(null, 'view')
 },
 filename: function (req, file, cb) {
 cb(null, file.fieldname)
 }
})

var upload = multer({ storage: storage })

// 页面渲染
app.get('/', function (req, res) {
 res.sendFile(path.join(__dirname, 'view/upload.html'));
})

app.post('/test', textParser, jsonParser, function (req, res) {
 log(req.body);
 var httpInfo = http.address();
 res.send({
 host: httpInfo.address,
 port: httpInfo.port
 })
})

// 对应前端的上传接口 http://127.0.0.1:3000/upload, upload.any() 过滤时不对文件列表格式做任何特殊处理
app.post('/upload', upload.any(), function (req, res) {
 log(req.files)
 res.send({message: '上传成功'})
})

// 监控 web 服务
var http = app.listen(3000, '127.0.0.1', function () {
 var httpInfo = http.address();
 log(`创建服务${chalk.green(httpInfo.address)}:${chalk.yellow(httpInfo.port)}成功`)
})

上传完毕后重新上传我没写动画重置,大家实际用的时候肯定是需要展示每个上传文件的,每次上传文件都对应着一个进度条,所以应该抽象为一个组件,至于组件的抽象我这就不详细写了,那个就很容易了。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
javascript实现的像java、c#之类的sleep暂停的函数代码
Mar 04 Javascript
鼠标移动到图片名上,显示图片的简单实例
Jul 14 Javascript
jquery 取子节点及当前节点属性值的方法
Aug 24 Javascript
javascript数组遍历for与for in区别详解
Dec 04 Javascript
JS获取各种宽度、高度的简单介绍
Dec 19 Javascript
jQuery trigger()方法用法介绍
Jan 13 Javascript
Jquery技巧(必须掌握)
Mar 16 Javascript
Angular4表单验证代码详解
Sep 03 Javascript
微信小程序使用modal组件弹出对话框功能示例
Nov 29 Javascript
浅谈React Native 传参的几种方式(小结)
May 21 Javascript
JS将时间秒转换成天小时分钟秒的字符串
Jul 10 Javascript
vue-cli —— 如何局部修改Element样式
Oct 22 Javascript
基于Express框架使用POST传递Form数据
Aug 10 #Javascript
Vue实现点击显示不同图片的效果
Aug 10 #Javascript
vue+eslint+vscode配置教程
Aug 09 #Javascript
一个手写的vue放大镜效果
Aug 09 #Javascript
详解Vue-cli3.X使用px2rem遇到的问题
Aug 09 #Javascript
微信小程序引入模块中wxml、wxss、js的方法示例
Aug 09 #Javascript
小程序Request的另类用法详解
Aug 09 #Javascript
You might like
优化NFR之一 --MSSQL Hello Buffer Overflow
2006/10/09 PHP
ThinkPHP水印功能实现修复PNG透明水印并增加JPEG图片质量可调整
2014/11/05 PHP
php利用scws实现mysql全文搜索功能的方法
2014/12/25 PHP
php正则匹配文章中的远程图片地址并下载图片至本地
2015/09/29 PHP
PHP htmlentities()函数用法讲解
2019/02/25 PHP
Laravel如何实现自动加载类
2019/10/14 PHP
Javascript异步表单提交,图片上传,兼容异步模拟ajax技术
2010/05/10 Javascript
javascript-简单的日历实现及Date对象语法介绍(附图)
2013/05/30 Javascript
js仿百度贴吧验证码特效实例代码
2014/01/16 Javascript
Javascript 按位取反运算符 (~)
2014/02/04 Javascript
jquery让指定的元素闪烁显示的方法
2015/03/17 Javascript
Javascript计算二维数组重复值示例代码
2016/12/18 Javascript
jQuery实现web页面樱花坠落的特效
2017/06/01 jQuery
JavaScript 数组去重并统计重复元素出现的次数实例
2017/12/14 Javascript
详解webpack2异步加载套路
2018/09/14 Javascript
vue循环数组改变点击文字的颜色
2019/10/14 Javascript
Vue3配置axios跨域实现过程解析
2020/11/25 Vue.js
python回调函数中使用多线程的方法
2017/12/25 Python
Python语言描述随机梯度下降法
2018/01/04 Python
numpy中的高维数组转置实例
2018/04/17 Python
Python将8位的图片转为24位的图片实现方法
2018/10/24 Python
python多线程并发及测试框架案例
2019/10/15 Python
pandas 中对特征进行硬编码和onehot编码的实现
2019/12/20 Python
Python类的绑定方法和非绑定方法实例解析
2020/03/04 Python
树莓派4B安装Tensorflow的方法步骤
2020/07/16 Python
使用简单的CSS3属性实现炫酷读者墙效果
2014/01/08 HTML / CSS
中国宠物用品商城:E宠商城
2016/08/27 全球购物
大学生毕业自我评价范文分享
2013/11/07 职场文书
办公室文书岗位职责
2013/12/16 职场文书
公司任命书范本
2014/06/04 职场文书
小学安全教育月活动总结
2014/07/07 职场文书
初中家长评语和期望
2014/12/26 职场文书
田径运动会通讯稿
2015/07/18 职场文书
2015大学党建带团建工作总结
2015/07/23 职场文书
2019客服个人年终工作总结范文
2019/07/08 职场文书
django注册用邮箱发送验证码的实现
2021/04/18 Python