javaScript 文件上传 - input 上传 和 webAPi 上传(解决上传对 input 的依赖)
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
- excludeAcceptAllOption
excludeAcceptAllOption:boolean
默认 false
,为 true
时隐藏选项
按钮及格式描述
multiple:同,多选
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 可放心测试