专栏名称: 前端早读课
我们关注前端,产品体验设计,更关注前端同行的成长。 每天清晨五点早读,四万+同行相伴成长。
目录
相关文章推荐
前端早读课  ·  【第3450期】JavaScript ... ·  2 天前  
前端早读课  ·  【早阅】MTO:最佳目标达成策略 ·  3 天前  
前端之巅  ·  纯血鸿蒙微信 App 正式上线!依然使用了 ... ·  3 天前  
51好读  ›  专栏  ›  前端早读课

【第3450期】JavaScript 中的千里眼和穿杨箭

前端早读课  · 公众号  · 前端  · 2025-01-24 08:00

正文

前言

提前祝大家春节快乐,节前就分享到今天了,2.5见。介绍了 JavaScript 中的文件系统访问 API(File System Access API),包括其定义、应用场景、优点,以及通过 Demo 讲解了核心概念和功能设计,如 Picker 和 Handle 的作用及使用方法,并提到了使用中的注意事项和未来的发展方向。今日前端早读课文章由 @Jax 授权分享。

正文从这开始~~

大家好,我是 Jax。

我做 Web 开发也有七年了,在写代码的过程中收获了非常多的乐趣,所以我一直坚持在社区中做分享,把知识和快乐传递给更多的人。

那今日份的快乐来自于 File System Access API,中文意思就是文件系统访问 API。

它是 JavaScript 中一套非常硬核的组合技,就好像千里眼和穿杨箭那样神奇。

为了方便表述,我们后面都简称为文件系统 API。

那我的分享会分成四个小节。

首先跟大家讲解到底什么是文件系统 API;

然后会结合实操代码,来了解这套 API 的核心概念和功能设计。

第三小节会介绍怎么更好地使用这套 API。

最后一小节我埋了一个小彩蛋,介绍一个神秘客串嘉宾。

如果只能用一句话来定义这套 API 是什么,那就是,它是 JavaScript 提供的一系列属性和方法,让我们能够访问到用户本地设备的文件和文件夹。

这么概括还是有点笼统。那我们除了要说什么是,还要说说说什么不是。

这样可以排除一些容易混淆的概念,加深理解。

文件 input 标签大家一定很熟悉,做文件上传组件总是少不了它,但它不属于这套 API 的范畴。

说到 input 标签,这里插播一条脑筋急转弯,说有一个父文件夹,里面嵌套了不知道多少层子文件夹,每个子文件夹里也不知道有多少文件。问,如何用最少的代码 —— 注意是最少的代码 —— 计算出这个文件夹中一共有多少文件?

大家有思路吗?那我先给大家炫儿一个,请看屏幕右侧。

我们先用一个文件 input 标签,与以往不同的是,我们给它加上一个 webkitdirectory 特性,这样就能上传整个文件夹了。

上传文件夹后,所有的文件就被自动提取到 files 数组中了。

这样,三行代码就能得到文件总数。大家回头可以试一试这个小窍门。

好我们回到正题,在 JavaScript 中,还有另外一套 API,叫「文件和目录入口」API,尽管名字和功能都很像,但确实不属于我们今天要聊的话题。

那在我看来,这套 API 整体上可以分为一前一后两个部分,前面的是 picker,用来提供用户界面来上传文件;后面的是 Handle,用于管理和操作所上传的文件。

所以,有了 Picker 和 Handle,凡是涉及到文件上传和处理的地方,都可以用上这套 API。

比如在线的文本编辑器、图片处理工具,以及视频剪辑应用等等。

我们来看一个真实案例。屏幕左侧这个界面是 Photopea,一个在线 P 图工具,类似 Photoshop。它支持用户上传本地文件,然后对图片进行编辑。

屏幕右侧的截图,是我在 Photopea 页面扒出来的和上传文件相关的代码逻辑。仔细看的话,能发现这里用的就是文件系统访问 API。

这套 API 不仅能用,而且非常好用。

它让 Web 应用能够穿透浏览器容器,触碰到用户本地的文件;而且带来了极强的文件操控能力,这就是为什么我把它比喻成千里眼和穿杨箭。

此外,它能与 IndexedDB、Web Worker 一起配合使用,具备持久化和并行能力。能带来原生级别的体验。

而且由于文件直接在前端代码里处理,无需上传云端,极大地保证了私密性,同时也为用户和我们自己节省了服务成本。

OK 以上和大家介绍了这套 API 的定义、应用场景和优点,接下来,我们结合一个 Demo,来深入了解一下这套 API 的核心概念和功能设计。

我们先来梳理一下核心概念。刚才我们提到,整体来看,这套 API 分为两个部分,前面是 Picker,后面是 Handle。

那么 PIcker 其实就是我们日常选择文件的系统弹窗,不同的操作系统,其 Picker 样式也不同。屏幕上这个是 MacOS 的 Picker 截图。

JavaScript 在 window 对象上提供了方法,让我们可以直接唤起 Picker 界面。我们首先来看选择文件的 Picker。

这个方法接收一些可选参数,我们简要介绍一下。

id 和 startsIn 都是用来指定快捷路径,帮用户提高操作效率。

multiple 用来控制是否多选。

这个名字老长的 excludeAcceptAllOption,简单理解就是否是限制文件类型,true 就是限制,false 就是不限制。如果为 true,那么就必须要设置下面这个 types 属性。我们可以把允许用户选择的文件类型放进去。

第二个 picker 是用来选择文件夹的 Picker,除了刚才讲的 id 和 startsIn,它还有一个 mode 参数,用来控制读写权限。

第三个 Picker 是用来选择保存文件的,我们可以向用户建议保存位置、类型,以及文件名。

OK,当用户通过 Picker 上传了文件之后,picker 方法会返回一个 Promise,这个 Promise fulfill 出来的对象,就是 API 的另一个核心概念:Handle。

对于这位憨豆先生,API 是这么设计的:顶层是一个基类 FileSystemHandle,具有一些公用的属性和方法;它下面有两个子类,分别对应文件和文件夹类型的 Handle。在日常使用过程中,我们都是使用子类实例,很少直接操作基类。

Handle 是对文件和文件夹入口的抽象,所以具有 name 和 kind 属性,name 对应文件或文件夹名;kind 的值可以是 file 或者 directory,可以帮我们区分类型。

同时它还有一些方法可以调用,比如判断两个实例是否指向同一个入口、移除入口等等。

而对于文件类型的 Handle,它支持对文件的读写,所以我们可以用 getFile 来拿到文件实体,以及用 createWritable 写入数据。

文件夹 Handle 在方法设计上会有很大不同,因为文件夹可能包含子文件和子文件夹,所以它支持在当前文件夹 Handle 上调用方法去获取子 Handle,也支持对子 Handle 做移除、重命名等操作。

好了,铺垫完了核心概念,我们来看一个具体的例子。这是我写的一个 Demo,这是一个微型的文件管理系统,用户可以选择一个文件夹来载入,然后就可以在 Web 页面上对文件夹内容进行管理了。支持的操作包括对文件和文件夹的增删改查,能够比较全面地体现这套 API 的强大能力。

接下来,我会带着大家逐一拆解这个 Demo 的核心功能。这样听我讲完一遍,大家也就基本能掌握这套 API 的用法了。

我们先来看怎么载入一个文件夹。这里我们要实现的是让用户选一个文件夹,我们来读取文件夹的下一级子内容,当然,你也可以按照深度或者广度遍历,把每一层都读取到。这里我们为了保持简洁,就只读下一层。

我们执行 showDirectoryPicker 拿到文件夹 Handle,再遍历它的子内容,从子内容的属性上可以拿到对应的名称和类型。

接着我们来看如何读取文件内容。

这里有两种方式,一种是直接让用户载入一个文件,另一种是已经载入了文件夹,从文件夹找子文件。

拿到文件 Handle 之后,通过 getFile 和 text 方法,就能读取到文件内容

那么如何新建文件和文件夹呢?

这里前提是我们已经拿到了根文件夹或者说父文件夹的 Handle,然后在父文件夹里新建。

我们用 Prompt 方法让用户输入名称,然后在父 Handle 上调用 getXXXHandle。这两个方法,如果只传 name,就是按名称查找子 Handle,而如果额外传了 create true,就代表新建了。

现在我们来实现重命名功能,同样是用 Prompt 获取用户输入值,用做新的名称,然后在文件 Handle 上调用 move 方法,就把文件名改了。

目前我还没找到重命名文件夹的方法,不过相信以后会有的。

接着我们来看编辑文件内容。我们知道,这实际上是在原有内容的基础上进行编辑,所以我们还是先执行读取文件内容的逻辑,拿到原来的文件内容。

在实现编辑界面上,你可以为文本内容配备上富文本编辑器,或者为图片配备图片编辑组件。这里为了最简化,我们以文本为例,把原有内容作为第二个参数传入 Prompt,这样,在浏览器弹出的输入框中,就会预填文件内容,用户就可以直接在里面编辑了。

用户编辑后,我们调用 createWritable,把编辑后的文本写入到原来的文件 Handle 中,这样,编辑文件功能就实现了。

最后我们来做删除功能。无论是文件还是文件夹,我们都可以在 Handle 上调用 remove 方法。区别在于,由于文件夹可能含有多级子内容,所以在删除时,需要传入 recursive: true。

好,通过刚才的 Demo,我们已经会用这套 API 了。但我们的目标不只是会用,更要用好。所以这一部分我来介绍一些需要注意的点,不保证全面,欢迎大家补充。

在使用这套 API 的过程中,我总结出三条原则:周全、克制、谨慎

这套 API 的部分功能还是实验性质的,这意味着两点

  • 各个浏览器的实现完整度是不一致的

  • API 功能可能会发生变化,比如某个方法会被废弃

因此,我们在使用 API 时,要总是先检测可用性,保证能够优雅降级。如果不想写重复的兼容代码,我们可以去 GitHub 上搜一些开源库来使用。

为了防止滥用和恶意攻击,我们需要遵守一些安全规则。

首先,这套 API 强制要求 https 来保证网络环境的安全。

其次,就像对音视频自动播放的限制一样,我们不能自动调用 showOpenFilePicker,上传文件和文件夹的行为需要由用户来触发,比如点击按钮等等。

再就是在同源网页下,用户首次在 Picker 中选择后,浏览器会弹窗提示用户是否进行后续操作。

第三个原则是谨慎。我们要树立数据无价的意识,涉及到操作用户文件的功能,比如增删改查本地数据,都需要在上线前进行充分的测试,确保在代码逻辑和业务流程上防止数据丢失。

同时也需要在交互上适时地提醒用户现在正在发生什么,帮用户合理地管理预期。

最后,我们最好是能够提供完善的回滚机制。比如我们要做一个在线 P 图工具,用户在修改后不满意是非常常见的,我们要允许用户再回到修改前的效果。

OK 以上就是关于文件系统访问 API 的全部内容了,我们聊了这套 API 是什么、有什么用、怎么用。希望这套强大的 JavaScript API 能够帮大家把灵感和创意落地,发挥出 Web 技术的强大威力。

接下来是彩蛋时间。

我们说文件系统访问 API 是千里眼,那么千里眼五米之内必有顺风耳,JavaScript 有另外一套 API,本地文件的任何风吹草动都能被监听到,它就是 File System Observer API。

这里也是我写的一个 Demo。

屏幕左侧的白色界面是一个 Web 版的文件夹监听器,右侧的深色界面是我在用 VS Code 对本地文件夹进行各种操作。可以看到,一举一动都能被记录下来。

如果大家感兴趣,那下次我们就聊 Observer API

关于本文
作者:@JaxNext
链接:https://juejin.cn/post/7446728060206546984

这期前端早读课
对你有帮助,帮” 
 “一下,
期待下一期,帮”
 在看” 一下 。