node+React如何实现上传文件夹功能?

node+React如何实现上传文件夹功能?


最近在完善自己的个人技术博客的时候,遇到了一个小问题,总所周知,上传文件功能是简单的,但不知道大家有没有写过上传文件夹的功能,如有需要,欢迎来看一下我的这篇文章。

技术栈

前端:React.js
后端:Express框架
用axios进行请求,后端用multer处理文件

前端代码

可能你还不知道,input 元素上还有一个的 webkitdirectory 属性。当设置了 webkitdirectory 属性之后,我们就可以选择目录了。

所选的文件中还会有一个webkitRelativePath属性,用于表示当前文件的相对路径。
在这里插入图片描述

import React from 'react';
import { Button, message } from "antd";
import { serverURL } from "@/apiConfig";
import axios from 'axios';
export default function AdminHome() {

  const folderInputRef = React.useRef(null);

  const styles = {
    hide: {
      display: "none",
    },
  };

  // 把文件夹分解成文件
  const handleFolderChange = (e) => {
    console.log(e.target.files.length);
    const list = Array.from(e.target.files);
    const files = list.map((file) => {
      if (file.webkitRelativePath) {
        const path = file.webkitRelativePath.split("/");
        const folders = path.slice(0, -1);
        file.folder = folders.join("#");
      }
      file.webkitRelativePath.replace(/\//g, "@");
      return file;
    });
    if (files.length > 0) {
      uploadFiles(files);
    }
    console.log('files', files);
    folderInputRef.current.value = "";
  };

  const MAX_COUNT = 1000;
  const MAX_SIZE = 1024 * 1024 * 1024;

  const uploadFiles = (files,idx = 0) => {
    if (files.length === 0) {
      return;
    }
    const list = Array.from(files);
    if (MAX_COUNT && list.length > MAX_COUNT) {
      message.error(`最多上传${MAX_COUNT}个文件`);
      return;
    }
    let isOverSize = false;
    if (MAX_SIZE) {
      isOverSize =
        list.filter((file) => {
          return file.size > MAX_SIZE;
        }).length > 0;
    }

    if (isOverSize) {
      message.error(`最多上传${MAX_SIZE / 1024 / 1024}M大的文件`);
      return;
    }
    // 设置文件类型
    // let isNotMatchType = false;
    // if (ACCEPS.length > 0) {
    //   isNotMatchType =
    //     list.filter((file) => {
    //       return ACCEPS.length > 0 && !ACCEPS.includes(file.type);
    //     }).length > 0;
    // }

    // if (isNotMatchType) {
    //   message.error("上传文件的类型不合法");
    //   return;
    // }
    let formData = new FormData();
    // 每次上传一个文件
    formData.append("files", files[idx], files[idx].webkitRelativePath.replace(/\//g, "@"));
    // 每次上传多个文件   可选,如果想要提升上传速度,可以选择一次上传多个文件,但上限为20个(亲测),超过20个可能会报错
    // files.forEach((file, i) => {
    //   formData.append(
    //     'files', 
    //     files[i],
    //     files[i].webkitRelativePath.replace(/\//g, "@")
    //   );
    // });
    // 你的服务器接口地址
    axios.post(serverURL + "/api/index/uploadFolder", formData)
      .then((res) => {
        console.log("res", res);
        if(idx<files.length-1){
          // 递归调用,可通过idx自行编写进度条
          uploadFiles(files,idx+1);
        }
        if(idx == files.length-1){
          message.success("上传成功");
        }
      })
      .catch((err) => {
        console.log("err", err);
        message.error("上传失败");
      })
  };

  return (
    <div>
      <Button onClick={() => folderInputRef.current.click()} type="primary">
        上传文件夹
      </Button>
      <input
        style={styles.hide}
        directory=""
        webkitdirectory=""
        onClick={(e) => e.stopPropagation()}
        onChange={handleFolderChange}
        multiple
        type="file"
        ref={folderInputRef}
      />

    </div>
  )
}

后端代码

安装multer

npm install --save multer

接口代码

// 公共接口部分
var express = require("express");
var router = express.Router();
const fs = require("fs");
const path = require("path");
const multer  = require('multer');

const UPLOAD_DIR = path.join(__dirname.replace("routes", "upload"));
const storage = multer.diskStorage({
  destination: async function (req, file, cb) {
    let relativePath = file.originalname.replace(/@/g, path.sep);
    let index = relativePath.lastIndexOf(path.sep);
    let fileDir = path.join(UPLOAD_DIR, relativePath.substr(0, index));
    // 确保文件目录存在,若不存在的话,会自动创建
    fs.mkdirSync(fileDir, { recursive: true });
    cb(null, fileDir);
  },
  filename: function (req, file, cb) {
    let parts = file.originalname.split("@");
    cb(null, `${parts[parts.length - 1]}`); 
  },
});
const upload = multer({storage: storage});

// 上传文件夹接口
router.post("/uploadFolder", upload.array('files', 1000),(req, res) => {
  console.log('req.files',req.files);
  if(req.files && req.files.length){
    res.send({
      code: 200,
      msg: "文件夹上传成功"
    })
  }else{
    res.send({
      code: 200,
      msg: "文件夹上传失败"
    })
  }
});

module.exports = router;

所遇到的问题

  1. 为了确保multer 能正确处理文件的路径,我们需要对路径进行特殊处理。即把 /斜杠替换为 @ 符号。
  2. 一次性上传100个文件会报错,建议一次性上传20个以下文件,比较保险

亲测代码有效,有需要上传文件夹功能的朋友,拿走不谢~~

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
React实现文件上传功能可以通过以下步骤进行: 1. 创建一个React组件,用于处理文件上传的逻辑和UI展示。 2. 在组件的state中定义一个变量,用于存储上传的文件。 3. 在组件的render方法中添加一个文件选择的input元素,并为其添加一个onChange事件处理函数。 4. 在onChange事件处理函数中,获取用户选择的文件,并将其存储到组件的state中。 5. 在组件的render方法中添加一个提交按钮,并为其添加一个onClick事件处理函数。 6. 在onClick事件处理函数中,使用FormData对象创建一个表单数据对象,并将上传的文件添加到表单数据中。 7. 使用fetch或axios等工具,将表单数据发送到服务器端进行文件上传。 8. 在服务器端接收到文件后,进行相应的处理和存储。 下面是一个简单的示例代码: ```javascript import React, { useState } from 'react'; function FileUpload() { const [file, setFile] = useState(null); const handleFileChange = (event) => { setFile(event.target.files[0]); }; const handleUpload = () => { const formData = new FormData(); formData.append('file', file); // 使用fetch或axios发送formData到服务器端进行文件上传 fetch('/upload', { method: 'POST', body: formData, }) .then(response => response.json()) .then(data => { // 处理上传成功后的逻辑 }) .catch(error => { // 处理上传失败后的逻辑 }); }; return ( <div> <input type="file" onChange={handleFileChange} /> <button onClick={handleUpload}>上传</button> </div> ); } export default FileUpload; ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值