前端项目实现图片的上传、删除等功能遇到的问题以及解决办法

前言

前端框架:React

图片上传:使用了Ant Design里的Upload上传组件

封装的图片上传组件

    import { Modal, Upload } from 'antd';
    import React, { useState, useEffect } from 'react';
    
    const UpLoadImage = (props) => {
      const [previewVisible, setPreviewVisible] = useState(false); // 预览图弹窗的开关
      const [previewImage, setPreviewImage] = useState(''); // 预览图的url
      const [previewTitle, setPreviewTitle] = useState(''); // 预览图的名称
      const [fileList, setFileList] = useState([]);// 图片列表

      const handleCancel = () => setPreviewVisible(false); // 关闭预览图的弹窗
      
      // 点击图片预览的事件
      const handlePreview = async (file) => {
          setPreviewImage(file.url || file.preview);
          setPreviewVisible(true);
          setPreviewTitle(file.name || file.url.substring(file.url.lastIndexOf('/') + 1)
        }
      };
      // 图片列表发生改变事件
      const handleChange = ({ fileList: newFileList }) => {
        setImageList(newFileList);
        props.handelImage(newFileList);
      };
      // 删除图片事件
      const handleRemove = (file) => {
        let fileListDelete = fileList;
        fileListDelete.forEach((item, i) => {
          if (item.uid == file.uid) {
            fileListDelete.splice(i, 1); // 找到之后删除
          }
        });
        setFileList(fileListDelete); // 更新图片列表
        props.handelImage(fileListDelete);
      };

      return (
        <>
          <Upload
            listType="picture-card"
            fileList={imageList}
            onPreview={handlePreview}
            onChange={handleChange}
            onRemove={handleRemove}
            multiple={true}
          >
            // 最多可传9张图片
            {imageList.length >= 9 ? null : <div>+</div>} 
          </Upload>
          <Modal
            visible={previewVisible}
            title={previewTitle}
            footer={null}
            onCancel={handleCancel}
          >
            <img alt="example" style={{ width: '100%'}}
              src={previewImage}
            />
          </Modal>
        </>
      );
    };

    export default UpLoadImage;

问题1

刚开始后端小伙伴需要我传递图片的url(字符串),通过逗号对url进行分隔

    param = {
        image: 'https://f.hotgrid.cn/api-v3AirApp/202208/acacd2be-120f-11ed-a66e-32b1894eb7cc.jpg,https:....'
    }

但我使用antd的组件上传本地的图片,拿不到图片的url,组件返回的数据如下:

image.png 然后跟后端小伙伴商量我把originFileObj作为参数放到一个数组里面传递过去,她那边来处理并生成图片的url再返回给我

但在请求接口的时候一直报错,问题出在了在传递File这种格式的数据时,接口的参数需要做一下处理

解决

export default function setData(options) {
  // 1.构造formData
  let formData = new FormData();
  // 2.遍历传递过来的参数-是一个对象
  for (const key in options) {
    // 3.判断当key值是image-图片参数
    if (key == 'image') {
      // 4.循环File数据的数组
      for (let i = 0; i < options[key].length; i++) {
        // 5.将这些图片对象的`file`对象一个个加入formData中,键名相同*,都是images。
        formData.append('images', options[key][i])
      }
    } else {
     // 6.其他的参数也需要加入到formData中
      formData.append(key, options[key]);
    }
  }
  const res = await axios({
    method: 'post', // 请求方式
    url: config.baseURL + config.constructionSourceAdd, // 接口地址
    data: formData, // 携带的参数
    headers: {
      'Content-Type': 'multipart/form-data', // 多文件上传需要添加的请求头
    },
  });
  return res.data;
}

formData对象文档 wangdoc.com/javascript/…

这下终于把图片成功上传到了数据库,但....

问题2

做完了上传图片的功能,接下来就要做删除图片的功能了,但问题来了 如果在图片列表中即存在由后端给我返回的图片(是一个数组,每一项是一个图片链接),又存在由本地选择的新的图片(是一个数组,但每一项里没有图片链接,只有File格式的数据),这个时候蒙圈了

因为是给我返回的图片链接,我没办法把这个链接转为File格式的数据,再一块作为参数传递过去。

这时候只好将之前写好的给改写掉,不把File格式的数据作为参数传递过去了,而是我自己将File格式的数据转换成链接再作为参数传递过去,保持统一性,

传输图片的File对象返回图片链接这个功能使用了后端小伙伴提供的一个接口

function handelImage(ImageFileArr){
    let imgUrl = await Promise.all(
      // ImageFileArr 是图片对象的数组集合
      ImageFileArr.map((item) => {
        return new Promise((r) => {
        // 提供的接口
          fetchUpload({
            files: item.originFileObj, // File数据
            subsystem_code: '...', //自定义的code码
            subsystem_api: '...', // 域名端口后的api
          }).then((res) => {
            r(res);
          });
        });
      })
    );
    let upLoadArr = imgUrl.map((item) => {
      // 拼接一下图片的链接
      return `https://f.hotgrid.cn/${item.result[0].url}`.toString();
    }).join(',');
    
    let param = {
        image: upLoadArr,
        ...
    }
}

这个时候就获取了由图片链接组成的一个数组再转为字符串由逗号分隔开,删除图片的时候更新ImageFileArr即可

image.png

如果我想保留旧的图片,并添加新的图片,因为旧的图片没有file数据,在处理ImageFileArr的时候将有file格式数据的添加进去,其他的则不添加。

最终的效果图

image.png

上传

image.png image.png

预览

image.png

完结

如果你觉得此文对你有帮助,点个赞,鼓励一下。

猜你喜欢

转载自juejin.im/post/7127257733560008741