日常随笔: 实现拖拽上传文件并展示

19. 拖拽上传图片并展示上传图片

1. 解决思路:

  • 通过利用,监听drop方法,从dataTransfer中得到上传的源文件
  • 利用FileReader类中的readAsDataURL将二进制文件转换成base64字符串
  • 将该字符串放入img的src中即可
  • 上传功能使用FormData进行处理,利用append方法添加内容
  • 之后利用post上传到服务器,获取文件地址
1. 核心处理

详细内容见注释

  • 浏览器读取文件并显示
const handleFileDrop = (e: React.DragEvent<HTMLDivElement>) => {
    //@ts-ignore
    e.preventDefault();
    // 获得拖动到页面上制定位置的文件内容
    const { files } = e.dataTransfer;
    const file = files[0];

    // 判断文件类型
    if (!file.type.startsWith("image")) {
        Notify.error("只能上传图片文件");
        return;
    }

    // 检验文件上传的大小
    if (!file) return;
    if (file.size > maxFileSize) {
        Notify.error("上传文件最大小不能超过10M");
        return;
    }
    // 读取文件到base64
    const reader = new FileReader();
    reader.readAsDataURL(file);
    // 当文件读取完毕时,保存为base64的字符串,后面img标签检测到变化后会自动渲染
    reader.onload = e => {
        const value = (e.target?.result as string) || "";
                       setFileUrl(value);
    };
    // 报错
    setFile(file);
};
  • 上传
const handleSubmit: IAvatarUploadProps["handleSubmit"] = async (
    file,
    setLoad
) => {
    setLoad(true);
    // 添加需要上传的文件
    const fileData = new FormData();
    fileData.append("file", file, file.name);
    // 添加完毕直接传就好了
    const { data } = await modifyAvatarApi(fileData);
    const { status, data: fileDetail, msg } = data;
    if (status) {
        const { filePath } = fileDetail;
        const { data } = await updateAvatarApi(userId, filePath);
        data.status ? Notify.success(msg) : Notify.error(msg);
        data.status &&
            (() => {
            dispatch({
                type: "login",
                payload: { ...state, avatarUrl: filePath }
            });
            setUserInfo({ ...userInfo, avatarUrl: filePath });
            window.localStorage.setItem("userToken", data.data.token);
        })();
        setLoad(false);
        closeDialog(dialogId);
    } else {
        Notify.error(msg);
    }
};

// 上传API
export const modifyAvatarApi: TModifyAvatar = (data: FormData) =>
  Axios.post(`${URL}/modifyAvatar`, data, {
    headers: { "Content-Type": "multipart/form-data" }
});
2. 注意几个坑

dragOver和drop事件中一定要阻止默认事件,不然的话会直接把图片文件在浏览器中显示,或者下载!!

2. 实现效果

3. 完整代码

import React, { useState } from "react";
import styles from "./style.module.scss";
import { Notify, Icon, Button, BlockLoading } from "zent";

export interface IAvatarUploadProps {
  maxFileSize: number;
  handleSubmit: (
    file: File,
    setLoad: React.Dispatch>
  ) => void;
}

export function AvatarUpload(props: IAvatarUploadProps) {
  const { maxFileSize, handleSubmit } = props;
  const [avatarFile, setFile] = useState();
  const [localUrl, setFileUrl] = useState();
  const [loading, setLoad] = useState(false);

  const handleDrageOver = (e: React.DragEvent) => {
    e.preventDefault();
  };

  const handleFileDrop = (e: React.DragEvent) => {
    //@ts-ignore
    e.preventDefault();
    const { files } = e.dataTransfer;
    const file = files[0];

    if (!file.type.startsWith("image")) {
      Notify.error("只能上传图片文件");
      return;
    }

    if (!file) return;
    if (file.size > maxFileSize) {
      Notify.error("上传文件最大小不能超过10M");
      return;
    }

    const reader = new FileReader();
    reader.readAsDataURL(file);
    reader.onload = e => {
      const value = (e.target?.result as string) || "";
      setFileUrl(value);
    };

    setFile(file);
  };

  return (
    
      
{!(avatarFile && avatarFile.name) ? (
{ 请选择你需上传的头像 }
) : ( <>
上传头像
处理后图片
处理后图片
)}
); }

你可能感兴趣的:(React学习笔记,日常开发,前端学习)