nodejs-使用multer实现多张图片上传,express搭建脚手架

  在工作中,我们经常会看到用户有多张图片上传,并且预览展示的需求.那么在具体实现中又该怎么做呢?

  本实例需要nodejs基础,本实例尽可能的在代码中实现了解读,如有疑惑点,欢迎提问。但是提问之前,希望你能先自行尝试解决,锻炼解决问题的能力。

  首先使用express脚手架生成,并且安装依赖

express --ejs
npm i

  在routes文件夹中建立/api/v1/img.js,在app.js中写入代码引入img.js,安装img.js依赖

app.use('/api/v1/img',require('./routes/api/v1/img'));
npm i multer moment

  HTML代码

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>图片上传</title>
<link rel="stylesheet" href="stylesheets/tinyImgUpload.css">
</head>
<body> <div id="upload"> </div>
<button class="submit">submit</button>
<script src="javascripts/tinyImgUpload.js"></script>
<script>
document.documentElement.style.fontSize = document.documentElement.clientWidth*0.1+'px'; var options = {
path: 'api/v1/img/file_upload',
onSuccess: function (res) {
console.log(res);
},
onFailure: function (res) {
console.log(res);
}
} var upload = tinyImgUpload('#upload', options);
document.getElementsByClassName('submit')[0].onclick = function (e) {
upload();
}
</script>
</body>
</html>

  JS代码

/**
* tinyImgUpload
* @param ele [string] [生成组件的元素的选择器]
* @param options [Object] [对组件设置的基本参数]
* options具体参数如下
* path 图片上传的地址路径 必需
* onSuccess(res) 文件上传成功后的回调 参数为返回的文本 必需
* onFailure(res) 文件上传失败后的回调 参数为返回的文本 必需
* @return [function] [执行图片上传的函数]
* 调用方法
* tinyImgUpload('div', options)
*/
function tinyImgUpload(ele, options) {
// 判断容器元素合理性并且添加基础元素
var eleList = document.querySelectorAll(ele);
if(eleList.length == 0){
console.log('绑定的元素不存在');
return;
}else if(eleList.length>1){
console.log('请绑定唯一元素');
return;
}else {
eleList[0].innerHTML ='<div id="img-container" >'+
'<div class="img-up-add img-item"> <span class="img-add-icon">+</span> </div>'+
'<input type="file" name="files" id="img-file-input" multiple>'+
'</div>';
var ele = eleList[0].querySelector('#img-container');
ele.files = []; // 当前上传的文件数组
} // 为添加按钮绑定点击事件,设置选择图片的功能
var addBtn = document.querySelector('.img-up-add');
addBtn.addEventListener('click',function () {
document.querySelector('#img-file-input').value = null;
document.querySelector('#img-file-input').click();
return false;
},false) // 预览图片
//处理input选择的图片
function handleFileSelect(evt) {
var files = evt.target.files; for(var i=0, f; f=files[i];i++){
// 过滤掉非图片类型文件
if(!f.type.match('image.*')){
continue;
}
// 过滤掉重复上传的图片
var tip = false;
for(var j=0; j<(ele.files).length; j++){
if((ele.files)[j].name == f.name){
tip = true;
break;
}
}
if(!tip){
// 图片文件绑定到容器元素上
ele.files.push(f); var reader = new FileReader();
reader.onload = (function (theFile) {
return function (e) {
var oDiv = document.createElement('div');
oDiv.className = 'img-thumb img-item';
// 向图片容器里添加元素
oDiv.innerHTML = '<img class="thumb-icon" src="'+e.target.result+'" />'+
'<a href="javscript:;" class="img-remove">x</a>' ele.insertBefore(oDiv, addBtn);
};
})(f); reader.readAsDataURL(f);
}
}
}
document.querySelector('#img-file-input').addEventListener('change', handleFileSelect, false); // 删除图片
function removeImg(evt) {
if(evt.target.className.match(/img-remove/)){
console.log('3',ele.files);
// 获取删除的节点的索引
function getIndex(ele){ if(ele && ele.nodeType && ele.nodeType == 1) {
var oParent = ele.parentNode;
var oChilds = oParent.children;
for(var i = 0; i < oChilds.length; i++){
if(oChilds[i] == ele)
return i;
}
}else {
return -1;
}
}
// 根据索引删除指定的文件对象
var index = getIndex(evt.target.parentNode);
ele.removeChild(evt.target.parentNode);
if(index < 0){
return;
}else {
ele.files.splice(index, 1);
}
console.log('4',ele.files);
}
}
ele.addEventListener('click', removeImg, false); // 上传图片
function uploadImg() {
console.log(ele.files); var xhr = new XMLHttpRequest();
var formData = new FormData(); for(var i=0, f; f=ele.files[i]; i++){
formData.append('images', f);
} console.log('1',ele.files);
console.log('2',formData); xhr.onreadystatechange = function (e) {
if(xhr.readyState == 4){
if(xhr.status == 200){
options.onSuccess(xhr.responseText);
}else {
options.onFailure(xhr.responseText);
}
}
} xhr.open('POST', options.path, true);
xhr.send(formData); }
return uploadImg;
}

  CSS代码

#img-container {

}
#img-container:after {
content: '.';
display: block;
height:;
visibility: hidden;
overflow: hidden;
clear: both;
}
.img-item {
position: relative;
float: left;
margin-right: 0.1875rem;
margin-bottom: 0.1875rem;
height: 2.34375rem;
width: 2.34375rem;
box-sizing: border-box;
}
.img-thumb {
border: 1px solid #000;
}
.thumb-icon {
width: 100%;
height: 100%;
}
.img-up-add {
display: table;
border: 1px dashed #E0E0E0;
}
.img-add-icon {
display: table-cell;
vertical-align: middle;
text-align: center;
}
.img-remove {
position: absolute;
right: -0.1875rem;
top: -0.1875rem;
display: block;
width: 0.375rem;
height: 0.375rem;
border-radius: 50%;
background: #f7333d;
color: #fff;
text-align: center;
text-decoration: none;
font-size: 0.25rem;
overflow: hidden;
background-clip: padding-box;
}
#img-file-input {
display: none;
}

  API

/*
* @Author: Carl Elias
* @Date: 2018-07-11 16:34:38
* @Last Modified by: Carl Elias
* @Last Modified time: 2019-03-26 20:04:56
*/ var express = require('express');
var fs = require('fs');
var multer = require('multer');
var router = express.Router();
const moment = require('moment'); //设置文件上传存储路径
var uploadDir = `./public/uploads/${moment().format('YYYYMMDD')}`;
fs.mkdirSync(uploadDir, {
recursive: true
}); // recursive 使用递归创建目录,如果父目录不存在会先创建 const storage = multer.diskStorage({ // 设置上传中间件
destination: function (req, file, cb) { // 上传路径
// console.log(file);
cb(null, uploadDir)
},
filename: function (req, file, cb) { // 上传之后的文件名
// console.log(file);
cb(null, Date.now() + '-' + file.originalname);
}
})
//设置multer upload
var upload = multer({
storage: storage
}).array('images'); //post请求 提交表单
router.post('/file_upload', function (req, res, next) {
//多个文件上传
upload(req, res, function (err) {
if (err) {
console.error('1.[System] ' + err.message);
} else {
//循环处理
var imgPath=[];
req.files.forEach(function (i) {
//获取临时文件的存储路径
imgPath.push(i.path);
console.log("i.path:",i.path)
}); //所有文件上传成功
//回复信息
var reponse = {
message: 'File uploaded successfully',
imgPath
};
//返回
res.end(JSON.stringify(reponse));
}
});
}); module.exports = router

  建议参考文档:

  multer官方中文文档

  Express官方中文文档

  前台界面设计者的GitHub库

  关于本文章页面效果,暂时仍有一些效果没有实现,后续将在本人的GitHub中进行持续更新,欢迎大家关注。

  最后,再次感谢Express官方,Multer官方,以及前台界面设计者的帮助。

  GitHub代码仓库

nodejs-使用multer实现多张图片上传,express搭建脚手架的更多相关文章

  1. node应用通过multer模块实现文件上传

    multer用于处理文件上传的nodejs中间件,主要跟express框架搭配使用,只支持表单MIME编码为multipart/form-data类型的数据请求. 如果要处理其他编码的表单数据可以通过 ...

  2. 微信小程序多张图片上传

    微信小程序上传图片每次只能上传一张,所有很多朋友就会问想要多张图片上传怎么办? 首先,我们来看一看wx.chooseImage(object)和wx.uploadFile(OBJECT)这两个个api ...

  3. js移动端/H5同时选择多张图片上传并使用canvas压缩图片

    最近在做一个H5的项目,里边涉及到拍照上传图片的功能以及识别图片的功能,这里对识别图片的功能不做赘述,不属本文范畴.我在做完并上线项目后,同事跟我提了一个要求是可不可以同时选择多张图片上传,我做的时候 ...

  4. H5单张、多张图片上传

    前言 今天我们聊一聊图片上传,单张Or多张 ,如今,各大图片上传插件数不胜数,例如:Jquery的 verupload.js,jQuery File Upload.Uploadify.jQuery.f ...

  5. UMeditor控制多张图片上传顺序

    多张图片上传的顺序,受到用户使用习惯.插件上传和插件插入页面顺序的影响. 估计是考虑到上传性能,官方没有提供UMeditor控制展示顺序的配置.在上传过程中,用户点击拖动的第一张图片,将作为文件数组中 ...

  6. JavaScript实现多张图片上传功能

    今天闲着没事,把之前的多张图片上传代码整理了下. 页面主要代码: <div class="upBox upBox2"> <div class="d1&q ...

  7. 用原生JS实现多张图片上传及预览功能(兼容IE8)

    最近需要做一个图片上传预览的功能(兼容IE8-11.chrome.firefox等浏览器),网上现有的文件上传组件(如webuploader)总是会遇到一些兼容性问题.于是我参考了一些博文(链接找不到 ...

  8. 【node】---multer模块实现图片上传---【巷子】

    1.安装muterl第三方模块 cnpm install multer --save 2.使用 multer在解析完成后,会向request对象中添加一个body对象和一个file或者files对象( ...

  9. 【nodejs】--express的中间件multer实现图片文件上传--【XUEBIG】

    Multer是nodejs中处理multipart/form-data数据格式(主要用在上传功能中)的中间件.该中间件不处理multipart/form-data数据格式以外的任何形式的数据 Tips ...

随机推荐

  1. 安装VC6.0安装步骤及心得体会

    一.安装步骤: 1.打开网站https://pan.baidu.com/s/nxee/AD ,输入提取密码:wdhk. 2.登录微信账号,将软件下载到D盘. 3.鼠标右键点击VC6.0快捷方式,选择“ ...

  2. oracle多行合并一行

    以上图为例 执行SQL语句: select d.group_id,to_char(wm_concat(d.tag)) from Imglib_Group_Tag d where d.group_id= ...

  3. Delphi窗体显示Echarts图表

    笨办法,先保存用着 unit Unit1; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Varian ...

  4. Yoink Mac版(临时文件存储助手)中文版

    Yoink Mac版是Mac上一款临时文件存储助手,当你拖动文件时Yoink for Mac就会出现,拖放文件到Yoink窗口中即可,需要文件时随时都能从Yoink窗口中拖出文件,使用非常便捷,小编准 ...

  5. request内置对象

    request内置对象(JSP九大内置对象之一)简述:内置对象即已在容器内部创建完成,可以直接调用的对象.容器在接收到客户端的请求后会创建一个对象用于处理请求信息,该对象就是内置对象(属于“javax ...

  6. MySQL 基础 查询

    别名 查询数据时,如果表名很长,使用起来不方便,此时,就可以为表取一个别名,用这个别名来代替表的名称 .同时为了更好的显示所查询出来的字段,也可以给字段取别名. 一,表作为别名: mysql> ...

  7. locust压测websocket协议

    Locust是以HTTP为主要目标构建的. 但是,通过编写触发器request_success和 request_failure事件的自定义客户端,可以轻松扩展到任何基于请求/响应的系统的负载测试 . ...

  8. (.NET高级课程笔记)委托、事件总结

      1.委托的声明.实例化和调用 同样的,也可以把事务写成上面的形式 2.泛型委托---Func.Action 3.委托的意义:解耦 4.委托的意义:异步多线程 5.委托的意义:多播委托 6.观察者模 ...

  9. vue组件弹窗

    定义弹窗组件 先写一个普通的vue组件,其显示的内容就是弹窗的内容. 文件的位置 /src/views/toast/toast.vue <template> <div class=& ...

  10. Intellij IDEA 配置Tomcat远程调试

    一.前言 在服务器端开发过程中,由于服务器环境差异导致运行结果不符合预期. 所以就需要到IDEA Debug 服务器代码.看起来貌似很高大上的事情. 今天就说说使用Intellij IDEA 配置的方 ...