跳至主要內容

javascript文件上传

h7mljavascriptjavascript大约 5 分钟约 1393 字

交互

点击上传多个文件 multiple

用户可以选择多个文件,然后文件列表会显示出来。需要注意的是,文件的选择是通过<input type="file" multiple>标签来实现的,其中multiple属性允许选择多个文件。

点击上传多个文件
const { useState, useEffect, ChangeEvent } = React;

export default () => {
  const [files, setFiles] = useState([]);
  const [fileList, setFileList] = useState([]);

  const handleChange = (e) => {
    const files = e.target.files;
    if (files) {
      setFiles(Array.from(files));
    }
  };

  useEffect(() => {
    const fileList = files.map((file) => file.name);
    setFileList(fileList);
  }, [files]);

  return (
    <div>
      <input type="file" multiple onChange={handleChange} />
      <ul>
        {fileList.map((file, index) => (
          <li key={index}>{file}</li>
        ))}
      </ul>
    </div>
  );
};

点击上传文件夹 odirectory

允许用户上传整个文件夹,而不仅仅是单个文件。使用<input type="file" webkitdirectory mozdirectory odirectory>标签来启用文件夹上传功能。在处理时,代码会检查文件是否为文件夹,然后递归读取文件夹中的文件列表。

webkitdirectorymozdirectoryodirectory是用于HTML文件输入元素<input type="file">的属性,用于启用文件夹上传功能。它们是浏览器厂商引入的一些非标准属性,因此在不同浏览器中的支持程度可能会有所不同。

webkitdirectory

支持浏览器: WebKit内核的浏览器,如Google ChromeSafari。作用: 当设置webkitdirectory属性时,文件输入框会打开一个文件选择对话框,允许用户选择文件夹而不仅仅是单个文件。这允许用户选择整个文件夹中的所有文件,而不必一个一个地选择。

mozdirectory

支持浏览器: Mozilla Firefox浏览器。作用: 类似于webkitdirectorymozdirectory属性用于启用文件夹上传功能。它允许用户在Firefox浏览器中选择整个文件夹进行上传。

odirectory

支持浏览器: 这是Opera浏览器引入的一个属性。作用: 类似于前两者,odirectory属性用于启用文件夹上传功能。用户可以在 Opera 浏览器中选择整个文件夹。需要注意的是,由于这些属性不是 HTML 标准的一部分,因此在不同浏览器中的支持可能不稳定。它们主要用于特定浏览器内核的实现,因此在跨浏览器应用程序中使用时,需要小心检查并处理不同浏览器的兼容性。在现代 Web 开发中,通常使用其他更标准的方法,如使用JavaScript来处理文件上传和文件夹选择,以确保跨浏览器兼容性。

const { useState, useEffect, ChangeEvent } = React;
export default () => {
  const [files, setFiles] = useState([]);
  const [fileList, setFileList] = useState([]);

  const handleChange = (e) => {
    const files = e.target.files;
    if (files) {
      setFiles(Array.from(files));
    }
  };

  useEffect(() => {
    const fileList = files.map((file) => file.name);
    setFileList(fileList);
  }, [files]);

  return (
    <div>
      <input type="file" webkitdirectory mozdirectory odirectory onChange={handleChange} />
      <ul>
        {fileList.map((file, index) => (
          <li key={index}>{file}</li>
        ))}
      </ul>
    </div>
  );
};

:::

拖拽上传文件和文件夹dataTransfer

拖拽上传文件和文件夹

用户可以将文件或文件夹拖拽到指定区域进行上传。代码使用onDragOveronDrop事件来处理拖拽操作,并通过e.dataTransfer.items来获取拖拽的文件和文件夹列表。

const { useState, useEffect, ChangeEvent } = React;

export default () => {
  const [files, setFiles] = useState([]);
  const [fileList, setFileList] = useState([]);

  const handleChange = (e) => {
    const files = e.target.files;
    if (files) {
      setFiles(Array.from(files));
    }
  };

  const handleDragOver = (e) => {
    e.preventDefault();
  };

  const handleDrop = (e) => {
    e.preventDefault();
    const files = e.dataTransfer.items;
    // 判断是否为文件夹
    for (const item of files) {
      const entry = item.webkitGetAsEntry();
      if (entry.isDirectory) {
        console.log('is directory');
        entry.createReader().readEntries((entries) => {
          console.log(entries);
          const fileList = entries.map((entry) => entry.name);
          setFileList(fileList);
        });
      } else {
        console.log('is file');
        entry.file((file) => {
          console.log(file.name);
          setFiles([file]);
        });
      }
    }
  };

  useEffect(() => {
    const fileList = files.map((file) => file.name);
    setFileList(fileList);
  }, [files]);

  return (
    <div>
      <input type="file" multiple onChange={handleChange} onDragOver={handleDragOver} onDrop={handleDrop} />
      <ul>
        {fileList.map((file, index) => (
          <li key={index}>{file}</li>
        ))}
      </ul>
    </div>
  );
};

如何实现多文件上传

  1. 把选择的文件放到一个数组里 files 一次性发送到服务器,服务器接收到后,再一次性处理
  2. 把选择的文件形成不同的请求,每个请求只处理一个文件一般会选择第二种,第一种方式,如果文件很多,其中一个文件上传失败,需要重新上传所有文件,很难保证对每一个文件的独立控制。第二种方式,需要控制并发数,如果并发数太大,可能会导致服务器崩溃,可以对于每个文件进行单独的控制,比如上传进度,上传取消等。

上传进度progress

使用XMLHttpRequest对象来发送文件,并通过xhr.upload.onprogress事件来监听上传进度。上传进度以百分比形式显示给用户。 ::: react-demo 上传进度

const { useState } = React;
export default () => {
  const [progress, setProgress] = useState(0);

  const handleUpload = (e) => {
    const file = e.target.files?.[0];
    if (file) {
      const xhr = new XMLHttpRequest();
      xhr.open('POST', '/upload');
      xhr.upload.onprogress = (event) => {
        if (event.lengthComputable) {
          const percentComplete = Math.round((event.loaded / event.total) * 100);
          setProgress(percentComplete);
        }
      };
      xhr.send(file);
    }
  };

  return (
    <div>
      <input type="file" onChange={handleUpload} />
      <p>{progress}%</p>
    </div>
  );
};

:::

如何实现上传进度追踪

上传进度追踪用户可以点击`Cancel`按钮来中止上传操作,这对于用户体验和控制非常有用。代码使用`xhr.abort()`方法来中止上传操作。
const { useState } = React;
export default () => {
  const [progress, setProgress] = useState(0);
  const [xhr, setXhr] = useState(null);

  const handleUpload = (e) => {
    const file = e.target.files?.[0];
    if (file) {
      const xhr = new XMLHttpRequest();
      xhr.open('POST', '/upload');
      xhr.upload.onprogress = (event) => {
        if (event.lengthComputable) {
          const percentComplete = Math.round((event.loaded / event.total) * 100);
          setProgress(percentComplete);
        }
      };
      xhr.send(file);
      setXhr(xhr);
    }
  };

  const handleCancel = () => {
    if (xhr) {
      xhr.abort();
      setXhr(null);
      setProgress(0);
    }
  };

  return (
    <div>
      <input type="file" onChange={handleUpload} />
      <p>{progress}%</p>
      {xhr && <button onClick={handleCancel}>Cancel</button>}
    </div>
  );
};