React + Node.js实现图片上传功能

 更新时间:2024年01月12日 09:32:57   作者:JacksonChen_  
最近笔者在开发个人博客的后台管理系统,里面用到了图片上传相关的功能,在这里记录并分享一下,希望可以帮到大家,话不多说直接开始吧,感兴趣的朋友可以参考下

效果

技术栈

前端:react+antdesign(upload组件)

后端:node+express+multer+uuid

前端

上传前

这边前端直接使用的 antdesign 所提供的上传组件,代码如下

       <Upload
              accept="multipart/form-data"
              name="avater"
              listType="picture-card"
              fileList={[]} // 手动设置空的 fileList
              className="avatar-uploader"
              showUploadList={false}
              beforeUpload={(file) => {
                handlePreview(file)
                return false // 阻止默认上传行为
              }}
            >
              {imageUrl ? <img src={imageUrl} alt="avater" style={{ width: '100%' }} /> : uploadButton}
            </Upload>

accept="multipart/form-data:是用于指定在 HTML 表单中上传文件时使用的编码类型。它告诉服务器将表单数据编码为 multipart/form-data 格式,这是用于上传文件的一种常见方式。

beforeUpload:则是需要在上传前对文件进行处理,我们来看一下代码里面发生了什么。

  const handlePreview = async (file: File) => {
    setImageUrl('')
    setLoading(true)
    const isImage = file.type.startsWith('image/')
    const isImageExtension = /\.(jpg|jpeg|png|gif)$/i.test(file.name)
 
    if (!isImage || !isImageExtension) {
      message.error(`${file.name} is not a supported image file`)
      return Upload.LIST_IGNORE
    }
 
    try {
      const reader = new FileReader()
      reader.onload = () => {
        setImageUrl(reader.result as string)
        setLoading(false)
      }
      reader.readAsDataURL(file)
    } catch (error) {
      console.error('图片预览失败', error)
      message.error('图片预览失败')
      setLoading(false)
    }
  }

首先判断文件的格式是不是图片类型的,如果不是,则终止上传。

    const isImage = file.type.startsWith('image/')
    const isImageExtension = /\.(jpg|jpeg|png|gif)$/i.test(file.name)
 
    if (!isImage || !isImageExtension) {
      message.error(`${file.name} is not a supported image file`)
      return Upload.LIST_IGNORE
    }

如果是图片类型则创建一个新的FileReader对象。

reader.readAsDataURL(file) 开始读取指定的文件,这里的 file 是一个文件对象,通过某种方式传递给这段代码。readAsDataURL方法会将文件内容读取为Data URL。

reader.onload设置一个事件处理程序,当文件读取完成时会触发该事件。

在读取完成时,触发 onload 事件。在这个函数中,通过 reader.result 获取读取到的Data URL,然后使用 setImageUrl 函数将其反显到页面当中。

    const reader = new FileReader()
      reader.onload = () => {
        setImageUrl(reader.result as string)
        setLoading(false)
      }
      reader.readAsDataURL(file)

这段上传前的代码是为了判断是否为图片类型,以及读取出来图片反显到页面当中,大家根据自己的需求调整。

反显效果如下:

上传

上传前准备工作以就绪,接下来就是点击上传,注意我这里因为有其他信息,需要一起上传。

如果只是单独的上传图片一个功能,antdesign 提供的有现成的代码,只需要在action属性写上后端地址即可。

点击上传

我们使用 antdesign 的表单提交功能,点击上传后得到一个values对象如下:

我们的图片信息在pic字段下,这个字段是自己设置的,下面是点击上传文件相关代码。

  const handleAddRequest = async (values: any) => {
    const formData = new FormData()
    if (values.pic && values.pic.fileList.length) {
      const file = values.pic.fileList[0].originFileObj
      formData.append('file', file, values.pic.fileList[0].name)
    }
 
    fetch(baseUrl + '/add-article', {
      method: 'POST',
      body: formData,
    })
      .then((res) => res.json())
      .then((res) => {
      })
      .catch((error) => {
      })
  }

首先创建一个新的 FormData 对象,用于构建表单数据。

const formData = new FormData()

检查是否存在图片信息(values.pic),并且图片文件列表(values.pic.fileList)不为空。

values.pic.fileList[0].originFileObj 则是获取这个文件对象的原始文件对象。 

将文件添加到 FormData

   const file = values.pic.fileList[0].originFileObj
   formData.append('file', file, values.pic.fileList[0].name)

注意 'file' 需要和后端读取文件的命名一致,等会后端会介绍。

最后只需要将整理好的formData对象放到body中发给后端即可!

后端

首先安装相关模块

npm i express //用于接口请求
npm i multer  //文件模块
npm i uuid    //文件命名

指定静态页面(图片存储文件夹)

app.use('/uploads/', express.static('./uploads')) //指定静态页面

解析Body数据

const bodyParser = require('body-parser')
app.use(bodyParser.json())

配置 multer 磁盘存储

const storage = multer.diskStorage({
  destination: function (req, file, cb) {
    cb(null, 'uploads/')//图片要存储的文件夹地址
  },
  filename: function (req, file, cb) {
    cb(null, uuid.v1() + '.' + file.originalname.split('.').pop())//存储的文件名
  },
})

使用配置好的存储创建multer实例

const upload = multer({ storage: storage })

定义一个用于添加文章的路由,支持文件上传

使用 upload.single('file') 作为中间件来处理带有字段名 'file' 的单个文件上传,这与上面前端上传的命名相对应( formData.append('file', file, values.pic.fileList[0].name))

app.post('/add-article', upload.single('file'), async (req, res) => {
  const filePath = 'uploads/' + req.file.filename // 获取上传文件存储的文件路径
  //todo....
})

最后上传的图片会存到uploads文件夹中

完整代码

由于整个项目不单单是这一个功能,这里就把上传图片功能所用到的前后端代码进行分享,有需要的同学可以参考一下代码!

前端

HTML      
 <Upload
              accept="multipart/form-data"
              name="avater"
              listType="picture-card"
              fileList={[]} // 手动设置空的 fileList
              className="avatar-uploader"
              showUploadList={false}
              beforeUpload={(file) => {
                handlePreview(file)
                return false // 阻止默认上传行为
              }}
            >
              {imageUrl ? <img src={imageUrl} alt="avater" style={{ width: '100%' }} /> : uploadButton}
            </Upload>
 
JS
##上传前操作
  const handlePreview = async (file: File) => {
    setImageUrl('')
    setLoading(true)
    const isImage = file.type.startsWith('image/')
    const isImageExtension = /\.(jpg|jpeg|png|gif)$/i.test(file.name)
 
    if (!isImage || !isImageExtension) {
      message.error(`${file.name} is not a supported image file`)
      return Upload.LIST_IGNORE
    }
 
    try {
      const reader = new FileReader()
      reader.onload = () => {
        setImageUrl(reader.result as string)
        setLoading(false)
      }
      reader.readAsDataURL(file)
    } catch (error) {
      console.error('图片预览失败', error)
      message.error('图片预览失败')
      setLoading(false)
    }
  }
 
##上传处理字段
  const handleAddRequest = async (values: any) => {
    const formData = new FormData()
    if (values.pic && values.pic.fileList.length) {
      const file = values.pic.fileList[0].originFileObj
      formData.append('file', file, values.pic.fileList[0].name)
    }
 
    fetch(baseUrl + '/add-article', {
      method: 'POST',
      body: formData,
    })
      .then((res) => res.json())
      .then((res) => {
      })
      .catch((error) => {
      })
  }

后端

const express = require('express')
const multer = require('multer') //文件上传模块
const uuid = require('uuid') //生成随机uuid-图片命名需要
app.use('/uploads/', express.static('./uploads')) //指定静态页面
//解析Body数据
const bodyParser = require('body-parser')
app.use(bodyParser.json())
 
 
const storage = multer.diskStorage({
  destination: function (req, file, cb) {
    cb(null, 'uploads/')
  },
  filename: function (req, file, cb) {
    cb(null, uuid.v1() + '.' + file.originalname.split('.').pop())
  },
})
 
const upload = multer({ storage: storage })
 
// 新增文章
app.post('/add-article', upload.single('file'), async (req, res) => {
  const filePath = 'uploads/' + req.file.filename//存储的文件名
  todo.....
})

以上就是React + Node.js实现图片上传功能的详细内容,更多关于React+Node.js图片上传的资料请关注脚本之家其它相关文章!

相关文章

  • React中组件优化的最佳方案分享

    React中组件优化的最佳方案分享

    React组件性能优化可以减少渲染真实DOM的频率,以及减少VD比对的频率,本文为大家整理了一些有效的React组件优化方法,需要的小伙伴可以参考下
    2023-12-12
  • react项目升级报错,babel报错,.babelrc配置兼容等问题及解决

    react项目升级报错,babel报错,.babelrc配置兼容等问题及解决

    这篇文章主要介绍了react项目升级报错,babel报错,.babelrc配置兼容等问题及解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-08-08
  • React 路由使用示例详解

    React 路由使用示例详解

    这篇文章主要介绍了React 路由使用,使用路由时需要为组件指定一个路由的path,最终会以path为基础,进行页面的跳转,具体使用先看个简单示例,该示例比较简单就是两个Tab页面的来回切换
    2022-05-05
  • react在安卓中输入框被手机键盘遮挡问题的解决方法

    react在安卓中输入框被手机键盘遮挡问题的解决方法

    这篇文章主要给大家介绍了关于react在安卓中输入框被手机键盘遮挡问题的解决方法,文中通过图文以及示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面来一起看看吧
    2018-09-09
  • React项目开发中函数组件与函数式编程关系

    React项目开发中函数组件与函数式编程关系

    函数组件和函数式编程究竟是什么关系呢?本文会围绕这个话题展开讲解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-11-11
  • React报错之组件不能作为JSX组件使用的解决方法

    React报错之组件不能作为JSX组件使用的解决方法

    本文主要介绍了React报错之组件不能作为JSX组件使用的解决方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-07-07
  • React实现基于Antd密码强度校验组件示例详解

    React实现基于Antd密码强度校验组件示例详解

    这篇文章主要为大家介绍了React实现基于Antd密码强度校验组件示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-01-01
  • 基于React+Redux的SSR实现方法

    基于React+Redux的SSR实现方法

    这篇文章主要介绍了基于React+Redux的SSR实现方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-07-07
  • React之错误边界 Error Boundaries示例详解

    React之错误边界 Error Boundaries示例详解

    这篇文章主要为大家介绍了React之错误边界Error Boundaries示例教程,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-10-10
  • React配置Redux并结合本地存储设置token方式

    React配置Redux并结合本地存储设置token方式

    这篇文章主要介绍了React配置Redux并结合本地存储设置token方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-01-01

最新评论