zoukankan      html  css  js  c++  java
  • nodejs-使用multer实现多张图片上传,express搭建脚手架

    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>
    View Code

      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;
    }
    View Code

      CSS代码

    #img-container {
    
    }
    #img-container:after {
        content: '.';
        display: block;
        height: 0;
        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;
    }
    View Code

      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
    View Code

      建议参考文档:

      multer官方中文文档

      Express官方中文文档

      前台界面设计者的GitHub库

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

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

      GitHub代码仓库

  • 相关阅读:
    利刃 MVVMLight 1:MVVMLight介绍以及在项目中的使用
    HTML5项目笔记10:使用HTML5 IndexDB设计离线数据库
    MySQL数据库安装
    安装维护手册
    XXX银行项目部署
    使用Excel批量给数据添加单引号和逗号
    sublime3 快速创建html模板
    Wyn Enterprise 报表查询面板三种实现方法汇总
    仪表板中选项卡外观样式详细设置讲解
    Wyn Enterprise 自助式分析(1)门户中的个人偏好设置
  • 原文地址:https://www.cnblogs.com/gitByLegend/p/10603446.html
Copyright © 2011-2022 走看看