Input标签能否同时支持上传文件和文件夹

510 阅读2分钟

Input经过目前我调研的情况是不能通过一个按钮实现同时支持上传文件和文件夹;除非一个下拉框选择文件或者文件夹上传;我知道的是Input可以同时支持单个文件,多个文件上传或者文件夹上传;(Ps:如果有大佬知道,还请在评论区告知一下,非常感谢)

interface FileInputProps
  extends DetailedHTMLProps<InputHTMLAttributes<HTMLInputElement>, HTMLInputElement> {
  webkitdirectory: string;
  directory: string;
}
export const CustomInputProps: FileInputProps = {
  webkitdirectory: 'true',
  directory: 'true',
};
<div `onClick={() => handleButtonClick()} className={`${styles['right-item']} ${styles['right-item-btn']}`}>导入</div>
 <input
        type="file"
        ref={inputRef}
        style={{ display: 'none' }}
        onChange={handleFileChange}
        multiple
        {...CustomInputProps}
      />
      
      
 const handleButtonClick = () => {
    // Programatically trigger file input click event
    inputRef.current?.click();
  };
  const handleFileChange = async (event: React.ChangeEvent<HTMLInputElement>) => {
      const files = event.target.files;
  }

题外话

DetailedHTMLProps

DetailedHTMLProps是TS中的一个泛型类型,用于描述HTML元素的属性。它主要用于定义React中组件props的类型,特别是针对原生HTML元素的props。 在React开发中,通常会使用DetailedHTMLProps来定义组件props的类型,以确保传入的props符合对应HTML元素的属性要求;

DetailedHTMLProps与HTMLAttributes的不同:

  • HTMLAttributes:是一个简单的泛型类型,用于描述HTML元素的属性。它提供了一种简单的方式来定义通用的HTML元素属性,适用于大多数HTML元素。通常用于定义组件props的类型,以确保传入的props符合对应HTML元素的属性要求;
  • DetailedHTMLProps是一个更加详细和精确的泛型类型,也用于描述HTML元素的属性。它接受两个参数:原生HTML元素属性的类型和对应HTML元素本身的类型。通过结合原生HTML元素属性的类型和元素本身的类型,可以更加精确和详细地对组件props进行定义。

将Input上传的文件转换为ArrayBuffer

  • 如果是chrome且大于75版本,可以使用File对象自带的file.arrayBuffer()方法转换;
  • 或者使用FileReader进行转换:
export function readBlobAsArrayBuffer(blob: Blob) {
  return new Promise((resolve, reject) => {
    try {
      const reader = new FileReader();
      reader.onload = function (event) {
        const arrayBuffer = event.target?.result;
        resolve(arrayBuffer);
      };
      reader.readAsArrayBuffer(blob);
    } catch (error) {
      reject(error);
    }
  });
}
 let arrayBuffer;
  if (isChromeXOrAbove(76)) {
    arrayBuffer = await file.arrayBuffer();
  } else {
    arrayBuffer = await readBlobAsArrayBuffer(file);
  }
      
//上传STL文件
let loader: null | STLLoader = new STLLoader();
let exporter: DRACOExporter | null = new DRACOExporter();
const box = new THREE.Box3();
const { configMap } = useGetConfigMap();
  
if (!loader) loader = new STLLoader();
const geometry = loader.parse(arrayBuffer as ArrayBuffer);
const mesh = new THREE.Mesh(geometry);
if (!exporter) exporter = new DRACOExporter();
const buffer = exporter.parse(mesh);
const key = file.name.replace('.stl', '');
if (configMap?.get(key)?.visible || !configMap?.get(key)) {
box.expandByObject(mesh);
}
const mutateUploadDrcData = await mutateUploadFile.mutateAsync({
datasource_uuid,
upload_task_uuid: currentTaskId,
property: {
  type: 'drc',
},
file: new Blob([buffer], { type: 'application/octet-stream' }),
file_path: file.webkitRelativePath.replace('.stl', '.drc'),
});
loader = null;

这里采用先创建一个上传任务(参数传递上传文件的类型,上传文件数),再上传文件,最后上传完成之后再请求一个上传完成的接口,结束当前上传任务