Input type=”file”

回顾下 Input type=”file” 的使用

<input type="file" name="" id="">

type=”file” 时的属性

accept

它定义了文件 input 应该接受的文件类型。这个字符串是一个以逗号为分隔的 唯一文件类型说明符 列表。由于给定的文件类型可以用多种方式指定,因此当你需要给定格式的文件时,提供一组完整的类型指定符是非常有用的。

<input type="file" id="docpicker"
  accept=".doc,.docx,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document">

capture

如果 accept 属性指出了 input 是图片或者视频类型,则它指定了使用哪个摄像头去这些数据。值 user 表示应该使用前置摄像头和/或麦克风。值 environment 表示应该使用后置摄像头和/或麦克风。如果缺少此属性,则 user agent 可以自由决定做什么。如果请求的前置模式不可用,则用户代理可能退回到其首选的默认模式。

multiple

当指定布尔类型属性 multiple, 文件 input 允许用户选择多个文件。

files

对象每个已选择的文件。如果 multiple 属性没有指定,则这个列表只有一个成员。

webkitdirectory (非标准属性,只能选择文件夹)

一个布尔值,表示是否仅允许用户选择一个目录(或多个目录,如果 multiple 也出现的话)

<input type="file" webkitdirectory >

use Web Api

大部分场景下使用 input 上传文件都会去选择隐藏 input 再 diy ui 很是麻烦,学会下面的 Api 将事半功倍(兼容堪忧请注意!:can i use)。

  • window.showOpenFilePicker()
  • window.showDirectoryPicker()
  • window.showSaveFilePicker()
<button id="upload">upload/save</button>

window.showOpenFilePicker

const upload = document.getElementById("upload");

const fileOptions = {
	types: [
		{
			description: '这只是一个描述', // 在选择文件时的格式描述
			accept: {
				'image/*': ['.png', '.gif', '.jpeg', '.jpg'],
				// "text/plain": [".txt"],
				// 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': ['.xlsx']
			}
		},
		{
			description: '上传 dmg',
			accept: {
				'text/plain': ['.dmg'],
			},
		},
	],
	excludeAcceptAllOption: true, // 为 true 时则不展示切换格式的选项(仅测试 Mac)
	multiple: true,
};

div.addEventListener('click', async () => {
	const result = await window.showOpenFilePicker(fileOptions);
	console.log(result);
	console.log(await result[0].getFile()); // file 信息 promise
})

options

  1. excludeAcceptAllOption

excludeAcceptAllOption:boolean 默认 false,为 true 时隐藏选项按钮及格式描述

  1. multiple:同,多选

  2. types

types 数组类型,表示允许保存的文件类型列表。数组中的每一项是包含以下属性的配置对象。

  • description(可选):用于描述允许保存文件类型类别
  • accept:是一个对象,该对象的 key 是 MIME 类型,值是文件扩展名列表。

window.showDirectoryPicker()

同上

window.showSaveFilePicker()

该 Api 为 window 接口中定义的方法,调用方法后会弹出可选择保存路径的文件选择器。

const FileSystemFileHandle = Window.showSaveFilePicker(options);

调用 showSaveFilePicker 方法之后会返回一个 FileSystemFileHandle 对象,可使用该方法上的 createWritable 方法写入数据至文件中。

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>showSaveFileDemo</title>
</head>
<body>
  <div>
    <button id="upload-btn">upload file</button>
  </div>

  <hr>

  <div>
    <button id="save-btn">save file</button>
  </div>
</body>

<script>
  const uploadBtn = document.getElementById('upload-btn');
  const saveBtn = document.getElementById('save-btn');

  let fileInfo = {};

  uploadBtn.addEventListener('click', async () => {
    try {
      const uploadFileOption = {
        types: [
          {
            description: '请上传 png',
            accept: {
              'text/plain': ['.png'],
            }
          }
        ],
        excludeAcceptAllOption: false,
      };

      const files = await window.showOpenFilePicker(uploadFileOption);
      const file = await files[0].getFile();
      if (file) fileInfo = file;
    } catch (e) {
      console.error(e, 'upload fail');
    }
  })

  const getFileBlob = (file) => new Promise(resolve => {
    resolve(new Blob([file]), { type: file.type });
  })

  saveBtn.addEventListener('click', async () => {
    try {
      const { name } = fileInfo;
      const fileName = name?.split('.')?.[0];
      const fileSuffix = name?.split('.')?.[1];

      const saveFileOption = {
        suggestedName: `${fileName}-${Date.now()}`, // 文件名称
        types: [
          {
            description: `保存为 ${fileSuffix}`,
            accept: {
              ['text/plain']: [`.${fileSuffix}`]
            }
          }
        ],
        excludeAcceptAllOption: false,
      };

      const handle = await window.showSaveFilePicker(saveFileOption);
      const writable = await handle.createWritable();
      await writable.write(await getFileBlob(fileInfo));
      await writable.close();
    } catch (e) {
      console.error(e, 'save fail')
    }
  });
</script>
</html>

Demo

上传和保存文件的 Demo,纯 js 可放心测试

showSaveFileDemo