学习网站建设有前景没,沈阳做网站的互联网公司,网站制作入门,网站建设需求多少钱大概JavaScript 两种方案打开文件对话框 文章目录JavaScript 两种方案打开文件对话框一、文件对话框二、传统方案表单元素#x1f308;三、文件系统访问API#x1f4a6;四、更进一步使用六、代码仓库#x1f310;七、参考资料#x1f498;七、推荐博文#x1f357;一、文件对话…
JavaScript 两种方案打开文件对话框 文章目录JavaScript 两种方案打开文件对话框一、文件对话框二、传统方案表单元素三、文件系统访问API四、更进一步使用六、代码仓库七、参考资料七、推荐博文一、文件对话框
在编写项目时难免会遇到想要用户上传文件的场景。文件流处理之前的第一关是打开文件对话框让用户选取文件本文主要讲解如何打开这个文件对话框同时带来了一种对于文件系统操作的新概念 API。要明确一点的是文件对话框是浏览器的功能开发者不能自定义文件对话框或是直接操作用户目录文件要做的只是指引用户打开文件对话框选中目录文件。 二、传统方案表单元素
在网上搜索教程想要打开文件对话框基本上都是使用 input typefile / 方案实现不用感到奇怪因为想在大多数浏览器上完全通过 JavaScript 脚本来控制文件对话框只能通过这个方法。这种传统方案历史最久最普遍当然兼容性也是最好的。通过脚本生成元素 input typefile / 并对其操作就能显示文件对话框同时生成的元素支持属性不变利用 accept 和 multiple 属性能控制文件上传类型与多选。
style.wrap {display: flex;height: 20vh;}#open-file {width: 100px;height: 50px;margin: auto;border: 1px solid #5B5B5B;border-radius: 5px;background-color: #FCFCFC;cursor: pointer;}#open-file:hover {background-color: #F0F0F0;}
/style
bodydiv classwrapbutton idopen-file选择文件/button/divscript/*** 打开文件选取对话框* param fn 选取文件后回调接收event和filelist参数* param accept 文件类型* param multiple 是否多选*/function openFilePicker({fn, accept, multiple} {}) {const inpEle document.createElement(input);inpEle.id __file_${Math.trunc(Math.random() * 100000)};inpEle.type file;inpEle.style.display none;// 文件类型限制accept (inpEle.accept accept);// 多选限制multiple (inpEle.multiple multiple);inpEle.addEventListener(change, event fn.call(inpEle, event, inpEle.files), {once: true});inpEle.click();}const btn document.getElementById(open-file);btn.addEventListener(click, () {openFilePicker({fn: (e, files) {console.group(获取到的文件);console.log(files, files);console.groupEnd();}});});/script
/body优缺点总结
不可避免得依靠生成表单元素才能实现实现起来比较繁琐。对于更进一步封装列如使用 Promise 在用户取消选择文件抛出 reject 变的难以检测如何监听取消行为在 stackoverflow 上貌似也没有什么好的解决办法不过也不用慌张大多数情况下只需处理文件获取后的行为。 三、文件系统访问API
文件系统访问API是一个很新的概念允许web应用程序直接读取或保存用户设备上的文件和文件夹的更改此 API 目前纯粹是一个 JavaScript API并且不与表单或输入元素集成这和以往的input typefile /不同。window.showOpenFilePicker 方法能够直接调用文件对话框一般配合aysnc/await使用获取到的是一个文件句柄对象数组。参数
multiple默认为false当设置为true是可以选择多个文件。excludeAcceptAllOption在打开文件对话框时右下角分类选项通常存在一个「所有文件」选项此属性控制该选项是否存在。默认为false则显示「所有文件」选项。types允许用户选择的文件类型数组数组中的每个元素都是一个对象对应文件对话框右下角分类的一个项。 description可选表示文件或则文件夹的描述对应文件对话框分类选项说明若为指定则浏览器自动生成。accept接受的文件类型传入对象键是MIME类型值是一个文件扩展名数组。浏览器能识别 MIME 类型的情况下会将扩展名数组与内置扩展名进行合并。「在传统方案 input typefile /里也存在一个类型属性 accept有意思的是只需要填入MIME类型即可浏览器会自动识别对应的后缀文件部分未认证或偏僻的MIME类型浏览器是识别不了猜测是为了解决这个问题将此参数以这种形式编写。需要了解更多MIME类型可以去查阅这篇文章『 『速查手册』MIME 多用途互联网邮件扩展 』」
下述示例限制只能传图片类型文件但事实上能支持的类型远远不止所设置的几个。注意因为兼容性问题运行下述代码请使用谷歌内核86版本浏览器。
style.wrap {display: flex;height: 20vh;}#open-file {width: 100px;height: 50px;margin: auto;border: 1px solid #5B5B5B;border-radius: 5px;background-color: #FCFCFC;cursor: pointer;}#open-file:hover {background-color: #F0F0F0;}
/style
bodydiv classwrapbutton idopen-file选择文件/button/divscriptconst btn document.getElementById(open-file);btn.addEventListener(click, async () {// 单元素数组结构const [fileHandle] await window?.showOpenFilePicker({types: [{description: 图片类型,accept: {image/*: [.png, .gif, .jpeg, .jpg]}}]});// 获取文件File对象const file await fileHandle?.getFile();console.group(获取到的文件);console.log(fileHandle);console.log(file);console.groupEnd();});/script
/body除了此方法外文件系统访问 API 还存在 showSaveFilePicker、showDirectoryPicker 方法等有兴趣可以去了解一下。 优缺点总结
最直观的好处使用 showOpenFilePicker 能够摆脱传统 input typefile /方式简单便捷极大程度上方便了 Web 应用的开发。受浏览器保护策略影响文件系统访问 API 程序不能自行运行需要用户对页面内容交互后才能触发。一般来讲对于文件的操作都是由用户交互所触发哪怕是传统方案 input typefile / 也需用户点击对此影响并不大。能够自定义兼容浏览器不能识别的 MIME 类型指定用户能够选择什么文件功能性更加强大。新的概念所带来的必然是兼容性问题且文件系统访问 API 不是 W3C 标准大多数浏览器并不能使用这是普及起来最大的问题许多开发者甚至没听说过此 API。 注意文件系统访问 API 它不是 W3C 标准也不在 W3C 标准轨道上在can i use上查询可知在谷歌内核以及少部分的浏览器上支持此 API 且版本要求苛刻。可以简单通俗的理解为这可能只是谷歌的工程师为谷歌浏览器专门开发的开发文档日志在火狐浏览器控制台上调用 window.showOpenFilePicker API 时返回的是未定义。 四、更进一步使用
有句话说的好小孩才做选择大人两个都要那么有没有什么办法可以实现传统方式与文件系统访问API相结合呢答案是肯定的。实现原理很简单只需根据 window 对象下判断是否存在 showOpenFilePicker 方法即可。下述代码引用博主 开源项目 的源码供大家参考。因为是使用 TypeScript 编写需要转换为 JavaScript 的同学需要使用 Node.js 安装 typescript依赖。
npm i typescript
tsc 文件目录 --target esnext /*** 打开文件选择对话框* 若浏览器不支持实验性方法window.showOpenFilePicker则采用input[typefile]元素进行兼容* param {string | string[]} accept 文件类型限制 默认全部* param {boolean} multiple 文件多选* param {boolean} webkitdirectory 只选择目录限制* param {number} compatible 兼容模式默认开启* param {number} cancel 兼容取消控制为0时候则取消文件时不抛出reject❗在使用async/await时会造成阻塞* param {string} description 文件或者文件夹的描述可选* return {PromiseFileList}*/
export async function openFileDialog({accept MIME.ALL,compatible true,cancel 300,multiple,webkitdirectory,description}: FileDialogConfig {}
): PromiseFile[] {accept.constructor Array (accept accept.join(,));// 实验性功能if (!compatible window.hasOwnProperty(showOpenFilePicker)) {console.warn(Note that showOpenFilePicker is an experimental interface and is not supported by most browsers, so use it sparingly.);const files [];const acceptMap: { [accept: string]: string[] } {};for (let a of (accept as string).split(,)) {acceptMap[a] [];}//ts-ignoreconst fileHandleList await window.showOpenFilePicker?.({multiple,excludeAcceptAllOption: false,types: [{description,accept: acceptMap}]});for (const f of fileHandleList) {files.push(await f.getFile());}return files;}const inpEle document.createElement(input);inpEle.id __file_${Math.trunc(Math.random() * 100000)};inpEle.type file;inpEle.style.display none;// 文件类型限制inpEle.accept accept as string;// 多选限制multiple (inpEle.multiple multiple);// 选择目录限制if (webkitdirectory) {console.warn(该特性是非标准的请尽量不要在生产环境中使用它\n This feature is non-standard, so try not to use it in a production environment!);inpEle.webkitdirectory webkitdirectory;}inpEle.click();return await new Promise((resolve, reject) {let _isSelected false;const changeEvent () {const files inpEle.files;if (files) {_isSelected true;resolve(Array.from(files));}};const focusEvent (event: Event) {if (event.target?.constructor Window) {setTimeout(() {!_isSelected reject(未选定文件\nUnselected file);}, cancel);}};inpEle.addEventListener(change, changeEvent, {once: true});cancel window.addEventListener(focus, focusEvent, {once: true});});
}六、代码仓库
https://github.com/xzcwx/files 七、参考资料
因发布平台差异导致阅读体验不同源文贴出《JavaScript 两种方案打开文件对话框》
官方手册 - HTML超文本标记语言 | MDNWindow.showOpenFilePicker() - Web APIs | MDN文件系统 API 的基本概念 - Web API 接口参考 | MDNcan i use 网络文献 The File System Access API: simplifying access to local filesW3C社区文档-文件系统访问英 七、推荐博文
『速查手册』MIME 多用途互联网邮件扩展『精』EditorConfig 小老鼠 跨编辑器 | IDE 保持一致的编码风格