渐进式 Web 应用:增强 PWA 的功能

1. 欢迎

在本实验中,您将使用现有的 Web 应用并为其添加高级功能。这是渐进式 Web 应用工作坊的一系列配套 Codelab 中的第六个。上一个 Codelab 是提示和衡量安装。本系列还有两个 Codelab。

学习内容

  • 使用 File System Access API 打开和保存用户文件系统中的文件
  • 使用 File Handling API 将已安装的 PWA 注册为文件处理程序
  • 选择合适的屏幕以使用多屏幕窗口放置 API 打开窗口
  • 使用 Screen Wake Lock API 防止屏幕进入休眠状态

注意事项

  • JavaScript

所需条件

  • 支持上述 API 的浏览器。对于某些 API,您可能需要使用具有有效开发者试用版或源试用版的浏览器才能完成。

2. 进行设置

首先,克隆或下载完成此 Codelab 所需的起始代码:

如果您克隆了代码库,请确保您位于 pwa05--empowering-your-pwa 分支中。该 ZIP 文件还包含相应分支的代码。

此代码库需要 Node.js 14 或更高版本。获得代码后,在代码的文件夹中通过命令行运行 npm ci,以安装所需的所有依赖项。然后,运行 npm start 以启动 Codelab 的开发服务器。

源代码的 README.md 文件提供了对所有分发文件的说明。此外,以下是您将在整个 Codelab 中使用的关键现有文件:

密钥文件

  • js/lib/actions.js - 为菜单提供基类

重要架构说明

在此 Codelab 中,您将全程修改 js/lib/action.js,该文件用于管理应用菜单中不同按钮的操作。您可以访问已初始化菜单的构造函数中的任何属性,其中包括主文本编辑器实例的 this.editor。在本 Codelab 中,您将使用两个重要的编辑器方法:

  • this.editor.setContent(content) - 将编辑器的内容设置为提供的内容实参
  • this.editor.content() - 获取编辑器的当前内容

3. 管理文件

借助 File System Access API,用户现在可以在自己的计算机上打开、保存和创建新文件。结合使用 File Handling API,让用户可以直接在 PWA 中打开文件,这样您的 PWA 就可以无缝集成到用户的日常生活中。

从应用内打开

要挂钩的第一个操作是能够从应用内打开用户文件系统中的文件。在 js/lib/actions.js 中,在 Actions 类的 open 方法中,编写执行以下操作的代码:

  • 打开文件选择器,该选择器将接受扩展名为 .md.markdowntext/markdown 文件
  • 将网页的标题设置为打开的文件名,再加上 PWA Edit
  • 将文件处理程序存储在 this.handler
  • 将编辑器的内容设置为文件的文本内容
  • 将处理程序保存到 settings-store IndexedDB 数据库中的 settings 对象存储区。

肯定:请注意,类构造函数不能是 async 函数,但您可以在其中调用 Promise。

现在,您可以在加载之间打开文件并保存打开的文件,但还需要做两件事:在应用加载时重新设置处理程序,并在用户重置应用时取消设置处理程序。

为了实现第一个目标,请在 js/lib/actions.jsActions 类的构造函数中执行以下操作:

  • 打开 settings-store 数据库
  • settings 对象存储区获取已保存的处理程序
  • 如果存在已保存的处理程序,则将 this.handler 设置为检索到的值,并将网页的标题设置为处理程序的文件名(加上 PWA Edit

为了重置应用的状态(可以通过 CTRL/CMD+Shift+R 完成),请更新 js/lib/actions.jsActions 类的 reset 方法,以执行以下操作:

  • 将文档标题设置为 PWA Edit
  • 将编辑器的内容设置为空字符串
  • this.handler 设置为 null
  • settings 对象存储区中删除已保存的处理程序

从用户的文件系统中打开

既然您现在可以从应用中打开文件,就应该允许用户使用文件打开您的应用!注册为设备的文件处理程序后,用户便可从文件系统中的任意位置在您的应用中打开文件。

负面:您可能需要启用开发者或源试用才能使此功能正常运行。如果您需要启用开发者试用版,建议您在 Chrome Canary 的副本中启用,而不是在常规浏览器中启用。如果您需要启用源试用,应照常注册,并将 标记添加到 index.html

首先,在 manifest.json 中添加一个 file_handlers 条目,该条目执行以下操作:

  • 开始营业时间:/
  • 接受 text/markdown,文件扩展名为 .md.markdown

这样一来,用户就可以使用您的应用打开文件,但实际上不会在您的应用中打开文件。为此,请在 js/lib/actions.jsActions 类中执行以下操作:

  • 在构造函数中添加 window.launchQueue 使用者,并使用处理程序(如果有)调用 this.open
  • 更新 this.open 以接受可选的启动处理程序
    • 如果该变量存在且是 FileSystemFileHandle 的实例,则将其用作函数的文件处理程序
    • 如果未显示,请打开文件选择器

完成上述两项操作后,安装 PWA 并尝试从文件系统中打开文件!

保存文件

用户可能需要采取两种不同的保存路径:将更改保存到已打开的文件中,或保存到新文件中。借助 File System Access API,保存到新文件实际上是创建新文件并获取文件句柄,因此首先,我们从现有句柄开始保存。

js/lib/actions.jsActions 类的 save 方法中,执行以下操作:

  • this.handler 获取处理程序,如果不存在,则从数据库获取已保存的处理程序
  • 创建文件处理程序的 FileSystemWritableFileStream
  • 将编辑器的内容写入流
  • 关闭数据流

能够保存文件后,就可以实现“另存为”功能了。为此,请在 js/lib/actions.jsActions 类的 saveAs 方法中执行以下操作:

  • 显示保存文件选择器,将其描述为 Markdown File,并使其接受扩展名为 .mdtext/markdown 文件
  • this.handler 设置为返回的处理程序
  • 将处理程序保存到 settings 对象存储区
  • 等待 this.save 完成,以便将内容保存到新创建的文件中

完成上述操作后,返回到 save 方法,检查 handler 是否存在,然后再尝试写入,如果不存在,则等待 this.saveAs 完成。

4. 显示预览

使用 Markdown 编辑器时,用户希望看到渲染输出的预览。使用 Window Management API,您可以在用户的主屏幕上打开渲染内容的预览。

在开始之前,请创建一个 js/preview.js 文件,并在其中添加以下代码,以便在加载时显示预览:

import { openDB } from 'idb';
import { marked } from 'marked';

window.addEventListener('DOMContentLoaded', async () => {
  const preview = document.querySelector('.preview');
  const db = await openDB('settings-store');
  const content = (await db.get('settings', 'content')) || '';

  preview.innerHTML = marked(content);
});

预览应以以下方式运行:

  • 当用户点击预览按钮且预览未打开时,系统应打开预览
  • 当用户点击预览按钮且预览处于打开状态时,应关闭预览
  • 当用户关闭或刷新 PWA 时,预览应关闭

按顺序执行这些操作,首先修改 js/lib/actions.jsActions 类中的 preview 方法,以执行以下操作:

  • 使用 Window Management API 获取可用的屏幕
  • 过滤屏幕以找到主屏幕
  • 打开一个窗口,用于显示标题为 Markdown preview/preview,该窗口占据主屏幕可用宽度的一半和整个可用高度,并位于主屏幕右半部分的整个可用空间内。可用尺寸不包括屏幕的预留区域,例如系统菜单栏、工具栏、状态栏或位置栏。
  • 将此打开的窗口保存到 this.previewWindow
  • 在该方法的顶部,检查 this.previewWindow 是否存在,如果存在,则关闭窗口并取消设置 this.previewWindow,而不是打开窗口预览

最后,在 js/lib/actions.jsActions 类的构造函数末尾执行以下操作:

  • beforeunload 活动期间关闭了 this.previewWindow

5. 专注模式

最后,我们希望为用户提供无干扰的写作模式。无干扰不仅意味着没有其他应用的杂乱信息,还意味着防止用户屏幕进入休眠状态。为此,您将使用 Screen Wake Lock API

唤醒锁定按钮的工作方式与预览按钮类似,可在开启和关闭状态之间切换。为此,请在 js/lib/actions.jsActions 类的 focus 方法中执行以下操作:

  • 检查文档是否具有全屏元素
  • 如果适合,请执行以下操作:
    • 退出全屏
    • 如果 this.wakeLock 存在,则释放唤醒锁定并重置 this.wakeLock
  • 如果没有,请执行以下操作:
    • 请求唤醒锁定信号并将其设置为 this.wakeLock
    • 请求使文档的正文进入全屏模式。

6. 恭喜!

您已了解如何使用 File System Access API 和 File Handling API 管理系统文件并将 PWA 与系统集成,使用 Window Management API 在不同屏幕上打开窗口,以及使用 Screen Wake Lock API 防止屏幕进入休眠状态。

本系列中的下一个 Codelab 是 Service Worker Includes