前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >antdesign + koa 实现图片上传

antdesign + koa 实现图片上传

作者头像
用户4793865
发布2023-01-12 16:25:08
7680
发布2023-01-12 16:25:08
举报
文章被收录于专栏:前端小菜鸡yym前端小菜鸡yym

「这是我参与2022首次更文挑战的第5天,活动详情查看:2022首次更文挑战

我们今天实现一下图片上传,前端用到的是antdesign中的文件上传,后端是自己封装的node的koa框架。

这个过程大致是:前端将图片提交给后端,后端将其存入后端项目的文件夹中,然后将图片所在路径返回给前端,前端得到图片路径后将图片路径再提交到后端保存的接口,存入数据库中

后端

在主文件中添加配置

我这个项目的配置文件在 app/index.js

图片上传的路径在 app/public/uploads

image.png
image.png

插件

koa-static

作用:声明一个静态文件夹,可以供上传图片找到。

安装:npm install koa-static

npm网址 : https://www.npmjs.com/package/koa-static

用法:

代码语言:javascript
复制
// 引入 koa-static
const koaStatic = require('koa-static');
// 引入koa
const Koa = require('koa');
// 实例化koa对象
const app = new Koa();
// 挂载
app.use(koaStatic(path.join(__dirname, 'public')))

koa-body

作用:配置koa的body体接收格式

安装:npm install koa-body

npm网址:https://www.npmjs.com/package/koa-body

用法:

代码语言:javascript
复制
const Koa = require('koa');
const koaBody = require('koa-body');
 
const app = new Koa();
 
app.use(koaBody());
app.use(ctx => {
  ctx.body = `Request Body: ${JSON.stringify(ctx.request.body)}`;
});

我们的配置 app/index.js

代码语言:javascript
复制
const Koa = require('koa')
const KoaBody = require('koa-body')
const path = require('path')
const koaStatic = require('koa-static')
const cors = require('koa2-cors');
const app = new Koa()
// 必须是一个函数
app.use(cors());
// 1. 文件上传到的路径 __diname是当前index.js所在的位置 public文件夹跟其同级
app.use(koaStatic(path.join(__dirname, 'public')))
// 2.在注册路由前注册
app.use(KoaBody({
    multipart: true,
    uploadDir: path.join(__dirname, 'uploads'),
    maxFileSize: 200 * 1024 * 1024,    // 设置上传文件大小最大限制,默认2M
    // 保留文件扩展名
    // keepExtensions: true,

}))

module.exports = app

添加路由

在router文件下的client.route.js中添加路由

image.png
image.png

这样添加后我们之后访问的路径就是 http://localhost:80001/client/Upload

Controller

在我们的controller文件夹下的client.controller.js中写入方法

image.png
image.png
代码语言:javascript
复制
  // 图片上传
    async Upload(ctx,next){
        // 前端的name要于此出 file相同 。 如果叫 img 前端组件也需要name='img'
        const file = ctx.request.files.file; // 获取上传文件

        console.log(ctx.request,'file')
        // 创建可读流
        const reader = fs.createReadStream(file.path);
        const random_num = random(16)
        const fileName = random_num+'.'+file.name.split('.')[1]
        let filePath = path.join(__dirname, '../app/public/uploads/') + `/${fileName}`;
        
        // 创建可写流
        const upStream = fs.createWriteStream(filePath);
        // 可读流通过管道写入可写流
        reader.pipe(upStream);
        最后将图片的存储路径返回
        ctx.body = {'url':`${ctx.origin}/uploads/${fileName}`}     
    }

前端

antdesgin对应的文档 :https://ant.design/components/upload-cn/

我们先看组件

代码语言:javascript
复制
import { Button, Input, Drawer, Form, Select, Tag, Upload, message } from 'antd';
      <Upload
              // 对应后端的 ctx.request.files.file
              name="file"
              listType="picture-card"
              className="avatar-uploader"
              showUploadList={false}
              action="/api/client/Upload"
              beforeUpload={beforeUpload}
              onChange={handleChange}
            >
              {imageUrl ? (
                <img src={imageUrl} alt="avatar" style={{ width: '100%', marginTop: '10px' }} />
              ) : (
                <div>
                  {loading ? <LoadingOutlined /> : <PlusOutlined />}
                  <div style={{ marginTop: 8 }}>Upload</div>
                </div>
              )}
            </Upload>

首先,注意name要和后端接收的名字对应上

代码语言:javascript
复制
// 后端对应代码
const file = ctx.request.files.file; // 获取上传文件

listType

上传列表的内建样式,支持三种基本样式 textpicture 和 picture-card 他们的样式也不相同。可以去官网具体看。

showUploadList

是否展示文件列表, 可设为一个对象,用于单独设定 showPreviewIconshowRemoveIconshowDownloadIconremoveIcon 和 downloadIcon

action

也就是 form表单写法的action方法,即提交对应的的后端路径。这里的 /api代理到了 localhost:8001

然后看用到的方法

代码语言:javascript
复制
 // 图片地址
  const [imageUrl, setImageUrl] = useState<string>();
  // 加载
  const [loading, setLoading] = useState(false);
  // 上传前
  const beforeUpload = file => {
    // 图片格式
    const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png';
    if (!isJpgOrPng) {
      message.error('You can only upload JPG/PNG file!');
    }
    const isLt2M = file.size / 1024 / 1024 < 2;
    if (!isLt2M) {
      message.error('Image must smaller than 2MB!');
    }
    return isJpgOrPng &amp;&amp; isLt2M;
  };
  // 转为base64
  const getBase64 = (img: Blob, callback: any) => {
    const reader = new FileReader();
    reader.addEventListener('load', () => callback(reader.result));
    reader.readAsDataURL(img);
  };
  // 上传图片
  const handleChange = (info: any) => {
    console.log(info.file, 'info');
    if (info.file.status === 'uploading') {
      setLoading(true);
      return;
    }
    if (info.file.status === 'done') {
      getBase64(info.file.originFileObj, (imageUrl: any) => {
        setImageUrl(imageUrl);
        setSubmitParams({ ...submitParams, cover: info.file.response.url });
        setLoading(false);
      });
    }
  };
  const handleUpload = e => {
    const file = e.target.files[0];
    console.log(file, 'hand');
  };

beforeUpload

图片提交前的处理函数

代码语言:javascript
复制
  // 上传前
  const beforeUpload = file => {
    // 图片格式
    const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png';
    if (!isJpgOrPng) {
      message.error('You can only upload JPG/PNG file!');
    }
    const isLt2M = file.size / 1024 / 1024 < 2;
    if (!isLt2M) {
      message.error('Image must smaller than 2MB!');
    }
    return isJpgOrPng &amp;&amp; isLt2M;
  };

handleChange

上传图片

代码语言:javascript
复制
  // 上传图片
  const handleChange = (info: any) => {
    console.log(info.file, 'info');
    // 上传过程中将loading状态设为true
    if (info.file.status === 'uploading') {
      setLoading(true);
      return;
    }
    // 上传完成 
    if (info.file.status === 'done') {
      getBase64(info.file.originFileObj, (imageUrl: any) => {
      // 设置图片路径
        setImageUrl(imageUrl);
        // 设置提交参数 我这个页是个大表单 图片只是一部分。我们要把上传图片接口返回的图片的
        // 存储路径返回
        setSubmitParams({ ...submitParams, cover: info.file.response.url });
        //上传完成将loading状态设为true
        setLoading(false);
      });
    }
  };

实现效果

image.png
image.png
image.png
image.png
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2022-01-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 后端
    • 在主文件中添加配置
      • 插件
    • 添加路由
      • Controller
      • 前端
        • 我们先看组件
          • 首先,注意name要和后端接收的名字对应上
          • listType
          • showUploadList
          • action
        • 然后看用到的方法
          • beforeUpload
          • handleChange
      • 实现效果
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档