vue、nodejs上传图片

演示

演示.gif

技术栈

  • 前端:Vue
  • 后端:nodejs、express、multer

本地端口

  • 前端:8080
  • nodejs:3000
  • nginx:3001

前端部分

<script>
    import axios from "@/axios";
    export default {
        data() {
            return {
                imgs: [] //已上传图片列表
            };
        },
        methods: {
            fileChange(e) {
                // 获取file文件
                const file = e.target.files[0];
                if (file.size / 1024 / 1024 > 5) {
                    alert("图片大于5M上传失败");
                    return;
                }
                // 通过FormData进行接口传输
                const formData = new FormData();
                formData.append("imgFile", file);
                // 接口上传
                axios.uploadImg(formData).then(response => {
                    if (response.code == 200) {
                        // 1、通过base64 预览
                        // let reader = new FileReader();
                        // reader.readAsDataURL(file);
                        // reader.onload = e => {
                        //     this.imgs.push(e.target.result);
                        // };
                        // 2、这里通过接口返回图片地址预览
                        this.imgs.push("//localhost:3001" + response.data);
                    }
                });
            }
        }
    };
</script>
<template>
    <div>
        <div class="photo">
            <div v-for="(img,index) in imgs" :key="index">
                <img class="upload-img" :src="img" alt />
            </div>
            <div class="default">
                <img src="@/assets/img/img_photo.png" alt />
                <input type="file" name="file" accept="image/*" @change="fileChange($event)" />
            </div>
        </div>
    </div>
</template>

axios.js

import axios from "axios";
const instance = axios.create();
axios.defaults.withCredentials = true;
//请求拦截器
instance.interceptors.request.use(
    config => {
        return config;
    },
    error => {
        return Promise.reject(error);
    }
);
//响应拦截器
instance.interceptors.response.use(
    response => {
        return Promise.resolve(response.data);
    },
    error => {
        return Promise.reject(error);
    }
);
export default {
    //上传图片
    uploadImg: data => {
        return instance.post("//localhost:3000/upload", data);
    }
};

流程:

  1. 通过input的onchange事件获取到本地图片文件。
  2. 调用接口传输FormData格式的图片文件。
  3. 拿到接口返回的服务器图片地址进行预览。

后端部分

const express = require('express')
const upload = require("../lib/upload");
const app = express();

// .single(fieldname)
// 接受一个以 fieldname 命名的文件。这个文件的信息保存在 req.file。
app.post('/upload', upload.single("imgFile"), function (req, res, next) {
    res.json({
        code: 200,
        data: "/" + req.file.filename,
        msg: "success"
    });
})

/lib/upload.js

const multer = require("multer");

const upload = multer({
    storage: multer.diskStorage({
        destination: "/uploads", //本地保存的目录(E:\uploads)
        filename: function(req, file, cb) {
            //保存的文件名
            cb(null, file.fieldname + "-" + Date.now() + "-" + file.originalname);
        }
    }),
    //限制上传大小5M和同时上传的数量
    limits: {
        fileSize: 1024 * 1024 * 5,
        files: 5
    },
    //依据mime文件类型过滤
    fileFilter: function(req, file, cb) {
        const allowArr = ["image/jpeg", "image/gif", "image/png"];
        if (allowArr.indexOf(file.mimetype) > -1) {
            cb(null, true);
        } else {
            cb(new Error("文件类型不正确"));
        }
    }
});

module.exports = upload;

当前端调用"/upload",在multer中间件,我们自定义了保存的目录、文件名,同时限制了大小、数量和文件类型。

最后返回给前端的数据data中,是一个自定义后的文件名。

为了让前端访问到保存后的文件,使用了nginx做代理。

Nginx代理

nginx.conf

server {
    listen       3001;
    server_name  localhost;
    location / {
        root   E:\uploads;
    }
}

代理的端口是3001,目录是我们自定义的保存目录"E:\uploads"。

这样前端<img>标签的src设置为"localhost:3001+图片名",就可以显示图片了。

后会有期。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,406评论 6 503
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,732评论 3 393
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,711评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,380评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,432评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,301评论 1 301
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,145评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,008评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,443评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,649评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,795评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,501评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,119评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,731评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,865评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,899评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,724评论 2 354