vue页面
上传组件
<template>
<div class="upload">
<el-upload
action=""
:class="{hide:isUpload}"
:auto-upload="autoUpload"
:http-request="upload"
list-type="picture-card"
multiple
:limit="limit"
:file-list="fileList"
:accept="accept"
ref="upload"
:name="name"
:on-change="handleChange"
:on-exceed="handleExceed"
>
<i slot="default" class="el-icon-plus"></i>
<div slot="file" slot-scope="{ file }">
<img class="el-upload-list__item-thumbnail" :src="file.url" alt="" />
<span class="el-upload-list__item-actions">
<span
class="el-upload-list__item-preview"
@click="handlePictureCardPreview(file)"
>
<i class="el-icon-zoom-in"></i>
</span>
<span
v-if="!disabled"
class="el-upload-list__item-delete"
@click="handleRemove(file)"
>
<i class="el-icon-delete"></i>
</span>
</span>
</div>
</el-upload>
<el-dialog :visible.sync="dialogVisible">
<img width="100%" :src="dialogImageUrl" alt="" />
</el-dialog>
</div>
</template>
<script>
export default {
name: "Upload",
props: {
accept: {
type: String,
default: "image/*"
},
limit: {
type: Number,
default: 5
},
name: {
type: String,
default: "file"
},
autoUpload: {
type: Boolean,
default: false
},
fileList: {
type: Array,
default() {
return [];
}
}
},
data() {
return {
dialogImageUrl: "",
dialogVisible: false,
disabled: false,
isUpload: false,
};
},
methods: {
handleChange(file, fileList) {
// 判断上传文件是否达到限制
this.isUpload = fileList.length >= this.limit
// 由于设置自动上传为false,before-upload钩子失效,所以在on-change中检验文件是否符合要求
const isJPG = ~["image/jpeg", "image/png"].indexOf(file.raw.type);
const isLt2M = file.raw.size / 1024 / 1024 < 2;
if (!isJPG) {
this.$message.error("上传图片只能是 jpg 格式!")
}
if (!isLt2M) {
this.$message.error("上传头像图片大小不能超过 2MB!")
}
if(!isJPG || !isLt2M){
// 不符合直接删除该文件
this.handleRemove(file)
}
},
// 删除图片
handleRemove(file) {
let fileList = this.$refs.upload.uploadFiles;
let index = fileList.findIndex(fileItem => {
return fileItem.uid === file.uid;
});
fileList.splice(index, 1);
// 由于删除组件有动画功能,所以设置个延迟显示
setTimeout(()=>{
this.isUpload = false
},1000)
},
// 预览图片
handlePictureCardPreview(file) {
this.dialogImageUrl = file.url;
this.dialogVisible = true;
},
// 文件超出限制的提示
handleExceed(file, fileList) {
this.$message.error("文件个数超出限制");
},
upload() {
// const formData = new FormData();
// const file = this.$refs.uploadImg.$refs.upload.uploadFiles;
// const headerConfig = {
// headers: { "Content-Type": "multipart/form-data" }
// };
// file.forEach(item => {
// formData.append("file", item.raw)
// });
// let {data:res} = await this.$http.post("upload/uploadTest", formData, headerConfig);
// console.log(res,'res');
}
}
};
</script>
<style lang="less" scoped>
// 设置上传为none,可以加个动画什么之类的
::v-deep .hide .el-upload--picture-card {
display: none;
}
</style>
父组件
<template>
<div class="box">
<div class="box1">
<Upload :fileList="fileList" ref="uploadImg" name="avater" />
</div>
<el-button class="btn" size="small" type="primary" @click="upload"
>确定上传</el-button
>
</div>
</template>
<script>
import Upload from "@/components/Upload";
export default {
components: { Upload },
data() {
return {
fileList: [],
};
},
created() {
},
methods: {
async upload() {
// 使用的是multer中间件,所以需要传递formdata格式的数据
const formData = new FormData();
// 找到需要传递的文件
const file = this.$refs.uploadImg.$refs.upload.uploadFiles;
// 设置请求头
const headerConfig = {
headers: { "Content-Type": "multipart/form-data" }
};
// 遍历 添加文件信息
// 注意:添加的字段名,需要与后端一样 "file"
file.forEach(item => {
formData.append("file", item.raw);
});
let { data: res } = await this.$http.post(
"upload/uploadTest",
formData,
headerConfig
);
},
}
};
</script>
<style lang="less" scoped>
.box1 {
margin: 50px 400px;
}
</style>
Nodejs服务器
const express = require('express');
const router = express.Router();
const multer = require('multer');
const db = require('../model/index')
const fs = require('fs');
const path = require('path');
const upload = multer({
storage: multer.diskStorage({
//设置文件存储位置
destination: function (req, file, cb) {
let date = new Date();
let year = date.getFullYear();
let month = (date.getMonth() + 1).toString().padStart(2, '0');
let day = date.getDate();
// 设置存储路径,由于我的静态资源目录是设置的 public,所以设置在 public 文件下
let dir = `public/uploads/${file.fieldname}/${year}${month}${day}`;
//判断目录是否存在,没有则创建
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, {
recursive: true
});
}
cb(null, dir);
},
//设置文件名称
filename(req, file, cb) {
// 重命名文件名,防止重复
let fileName = file.fieldname + '-' + Date.now() + '-' + file.originalname
cb(null, fileName);
}
})
});
// 常用的两方法:多选用 array(),单选用single()
const multipleFile = upload.array('file', 3)
router.post('/uploadTest', (req, res, next) => {
multipleFile(req, res, err => {
if (err instanceof multer.MulterError) {
console.log('---errMulterError---', err);
} else if (err) {
console.log('---err---', err);
}
console.log(req.files, 'req.files');
for (let i = 0; i < req.files.length; i++) {
let sql = "INSERT INTO test VALUES (NULL,?)"
// 重新设置存储在数据库的 url 地址,去掉前面的public字符串方便读取
let destination = req.files[i].destination.substring(6)
let url = `${destination}/${req.files[i].filename}`
// console.log(url, 'path');
db(sql, [url], function (err, data) {
console.log('err', err);
if (err) {
res.json({
code: 500,
msg: '服务器报错,请稍后重试'
})
} else {
res.json({
code: 200,
msg: '服务器响应成功',
data: data,
})
}
})
}
})
})
module.exports = router;