最近用vue 和node,koa写后台管理项目,后台用element ui 上传图片时,遇到很多坑,查了很多方法,解决后尽可能详尽的记录了下来
解决几个问题
– 如何把文件上传到node 文件夹中
– 如何重新命名文件名字,防止文件名字重复,传入数据库中
– 如何正确的对应数据库中图片地址和文本内容
– 如何直接访问链接显示图片
1.node部分
//npm 下载
const bodyParser = require("koa-bodyparser");
const multer = require("@koa/multer");
const cors = require("koa-cors");
app.use(cors()); //跨域插件
app.use(bodyParser()); //引入post 中间件用来处理post请求,不能喝koa-body共用
app.use(router.routes()); //启动路由
app.use(router.allowedMethods()); //接收get
//使用KoaStatic,绑定目录为./public/upload,直接用‘地址/文件名访问’
// app.use(KoaStatic("./public/upload"));
app.use(KoaStatic(path.join(__dirname, "./public/upload")));
let imgName;
//文件保存设置
const storage = multer.diskStorage({
// destination: function (req, file, cb) {
// cb(null, path.join(__dirname, "/public"));
// },
// 文件保存路径, 这里需要自己手动到public下面新建upload文件夹。
destination: function (req, file, cb) {
cb(null, "public/upload");
},
//文件名字设置
filename(req, file, cb) {
// logger.debug(req);
console.log(file);
let fileFormat = file.originalname.split("."); //以点分割成数组,数组的最后一项就是后缀名
//文件名字,时间+原文件名字,防止文件名字重复
let fileNowName =
Date.now() + fileFormat[0] + "." + fileFormat[fileFormat.length - 1];
imgName = fileNowName; //记录改变后的文件名字
cb(null, fileNowName);
},
});
//文件上传限制
const limits = {
storage: storage,
limits: {
fileSize: 1024 * 1024 * 4, // 限制4m
},
};
const upload = multer({ storage, limits });
//上传图片,获取图片名字返回,对应el ui的action地址,upload.single("file")被调用,imgName更新此次图片地址,返回此次上传文件处理后名字
router.post("/add", upload.single("file"), async (ctx) => {
// 返回结果给前端
ctx.body = {
mesg: "ok",
imgName,
};
});
//图片和表单数据存入存入数据库
router.post("/add-news", upload.single("file"), async (ctx) => {
const { title, img, text } = ctx.request.body;
console.log();
//这里传入img,如果没有图片,前端传值时将img设为“无”
if (img == "无") {
mysql.query(
`INSERT INTO news (title,img,text) VALUES ('${title}','无','${text}')`
);
} else {
// 写入数据库,config.http + img,config.http静态服务器地址,可以用koa-static,img为前端接收第一次传回的文件名字,在传入这个接口
mysql.query(
`INSERT INTO news (title,img,text) VALUES ('${title}','${
config.http + img
}','${text}')`
);
}
ctx.body = {
mesg: "ok",
};
});
app.listen(config.port); //localhost:config.port
console.log(`listening on port ${config.port}`);
2.el 部分 记住文件name 名字file 和后端upload.single(“file”)一样,
<el-upload
class="upload-demo"
name="file"
action="http://localhost:3000/add"
ref="upload"
:auto-upload="false"
:on-preview="handlePreview"
:on-remove="handleRemove"
:before-upload="beforeAvatarUpload"
:on-success="handleAvatarSuccess"
list-type="picture"
>
<el-button size="small" type="primary">点击上传</el-button>
<div slot="tip" class="el-upload__tip">
只能上传jpg/png文件,且不超过4m
</div>
</el-upload>
<el-button type="primary" @click="submitForm('ruleForm')"
>立即发布</el-button
3.vue 部分
data() {
return {
ruleForm: {
title: "",
text: "",
},
textLength: 0,
rules: {
title: [
{ required: true, message: "请输入新闻标题", trigger: "blur" },
{ min: 3, max: 5, message: "长度在 3 到 5 个字符", trigger: "blur" },
],
},
loading: false, //element ui 的加载框
IsFile: false, //判断是否有文件
};
},
methods: {
// 图片上传限制
beforeAvatarUpload(file) {
const isJPG = file.type === "image/jpeg" || file.type === "image/png";
const isLt2M = file.size / 1024 / 1024 < 4; //文件大小4m
console.log(file.uid);
if (file.uid) {
// this.Isimg = false;
this.IsFile = true; //有图片
} else {
this.IsFile = false;
}
if (!isJPG) {
this.$message.error("上传图片是 JPG,png格式!");
this.loading = false;
}
if (!isLt2M) {
this.$message.error("上传图片大小不能超过 4MB!");
this.loading = false;
}
return isJPG && isLt2M;
},
//上传图片成功,成功后发送表单
handleAvatarSuccess(res, file) {
console.log(res);
// console.log(file);
if (res.mesg == "ok") {
//进行往数据库提交接口
request({
method: "post",
url: "/add-news",
data: {
title: this.ruleForm.title,
img: res.imgName, //图片上传成功后返回图片名字
text: this.ruleForm.text,
},
})
.then((res) => {
this.loading = false;
console.log(res);
this.navTo("/home/news-info/news-list");
})
.catch((err) => {
console.log(err);
});
}
},
//提交表单
submitForm(formName) {
//数据检验
this.$refs[formName].validate((valid) => {
if (valid) {
console.log("submit!");
} else {
console.log("error submit!!");
return false;
}
});
this.loading = true;
setTimeout(() => {
this.$refs.upload.submit();
// 若果没有图片,直接发送表单
console.log(this.IsFile);
if (!this.IsFile) {
// console.log(this.Isimg);
this.loading = false;
//axios 请求
request({
method: "post",
url: "/add-news",
data: {
title: this.ruleForm.title,
img: "无",
text: this.ruleForm.text,
},
})
.then((res) => {
// console.log(res);
this.navTo("/home/news-info/news-list");
})
.catch((err) => {
console.log(err);
});
// this.navTo("/home/news-info/news-list");
}
}, 500);
},
//移除图片
handleRemove(file, fileList) {
console.log(file, fileList);
},
//预览
handlePreview(file) {
console.log(file + "11");
},
// 文章内容限制,这是我做的文件编辑,可以删除
alertValue(e) {
e.quill.deleteText(800, 1); //设置文字数量限制
console.log(e.quill.getLength() - 1);
this.textLength = e.quill.getLength() - 1;
this.IsWriteText = false;
},
//路由跳转
navTo(routerUrl) {
console.log(routerUrl);
this.$router.push({
path: routerUrl,
query: {},
});
},
},