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