Vue+koa+node 结合element Ui 实现后台图片上传数据库

最近用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: {},
      });
    },
  },
  • 1
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值