窗口管理

浏览器之外的 PWA 会管理自己的窗口。在本章中,您将: 了解可用于在应用内管理窗口的 API 和功能 操作系统

PWA 窗口

在由 PWA 管理的您自己的窗口上运行,具有该操作系统中任何窗口的所有优势和责任,例如:

  • 在多窗口操作系统(例如 Windows 或 ChromeOS)中,能够调整窗口大小并四处移动窗口。
  • 与其他应用窗口共享屏幕,例如在 iPadOS 分屏模式或 Android 分屏模式下。
  • 在桌面设备上的程序坞、任务栏和 Alt-Tab 菜单中展示,在移动设备上显示在多任务窗口列表中。
  • 能够最小化窗口,跨屏幕和桌面移动窗口,以及随时将其关闭。

移动窗口和调整窗口大小

PWA 窗口可以任意尺寸,并且可以在桌面操作系统的屏幕上任意位置放置。默认情况下,当用户在安装后首次打开 PWA 时,PWA 的默认窗口大小为当前屏幕百分比,且最大分辨率为 1920x1080(位于屏幕左上角)。

用户可以移动窗口并调整其大小,浏览器会记住最后一次使用的偏好设置,因此用户下次打开应用时,窗口将保留上次使用时的大小和位置。

您无法在清单中定义 PWA 的首选尺寸和位置。您只能使用 JavaScript API 调整窗口的位置和大小。在代码中,您可以使用 window 对象的 moveTo(x, y)resizeTo(x, y) 函数移动自己的 PWA 窗口并调整其大小。

例如,您可以通过以下方式调整 PWA 窗口的大小和移动 PWA 窗口的大小:

document.addEventListener("DOMContentLoaded", event => {
   // we can move only if we are not in a browser's tab
   isBrowser = matchMedia("(display-mode: browser)").matches;
   if (!isBrowser) {
      window.moveTo(16, 16);
      window.resizeTo(800, 600);
   }
});

您可以使用 window.screen 对象查询当前屏幕尺寸和位置;您可以使用 window 对象中的 resize 事件来检测窗口大小调整的时间。没有用于捕获窗口移动的事件,因此您可以选择频繁查询位置。

浏览其他网站

如果您要将用户转到 PWA 范围之外的外部网站,可以使用标准 <a href> HTML 元素、使用 location.href 或在兼容平台上打开一个新窗口。

目前在所有浏览器上,如果安装了 PWA,当您浏览到清单范围以外的网址时,PWA 的浏览器引擎会在窗口上下文中呈现应用内浏览器。

应用内浏览器的部分功能如下:

  • 它们会显示在您的内容之上。
  • 它们具有一个显示当前源、窗口标题和菜单的静态网址栏。通常,它们使用清单的 theme_color 为主题。
  • 通过上下文菜单,您可以在浏览器中打开该网址。
  • 用户可以关闭浏览器或返回。

在桌面 PWA 上浏览超出范围的网址时,使用应用内浏览器。

在独立 PWA 中浏览不在报告范围内的网址时,iPhone 上的应用内浏览器。

Android 设备上的应用内浏览器(在独立 PWA 中浏览不涵盖的网址时)。

授权流程

许多网络身份验证和授权流程都涉及将用户重定向到其他来源中的其他网址,以获取将返回到 PWA 来源的令牌(例如使用 OAuth 2.0)。

在这些情况下,应用内浏览器会遵循以下流程:

  1. 用户打开您的 PWA 并点击“登录”。
  2. 您的 PWA 会将用户重定向到 PWA 范围之外的网址,以便呈现引擎会在 PWA 中打开应用内浏览器。
  3. 用户可以随时取消应用内浏览器并返回到 PWA。
  4. 用户登录应用内浏览器。身份验证服务器会将用户重定向到您的 PWA 源,并以参数形式发送令牌。
  5. 当应用内浏览器检测到属于 PWA 作用域的网址时,浏览器会自行关闭。
  6. 引擎会将主 PWA 窗口导航重定向到身份验证服务器在应用内浏览器中访问的网址。
  7. 您的 PWA 会获取令牌、存储令牌并呈现 PWA。

强制浏览器导航

如果您想使用网址(而不是应用内浏览器)强制打开浏览器,则可以使用 <a href> 元素的 _blank 目标。这仅适用于桌面 PWA;在移动设备上,用户无法通过网址打开浏览器。

function openBrowser(url) {
    window.open("url", "_blank", "");
}

打开新窗口

在桌面设备上,用户可以在同一 PWA 中打开多个窗口。每个窗口都是指向同一 start_url 的不同导航方式,就像您打开了同一个网址的两个浏览器标签页一样。 在 PWA 的菜单中,用户可以依次选择“文件”和“新窗口”,通过 PWA 代码,您可以使用 open() 函数打开一个新窗口。如需了解详情,请参阅文档

function openNewWindow() {
    window.open("/", "new-window", "width=600,height=600");
}

同一个安装式 PWA,在桌面操作系统中打开多个窗口。

在 iOS 或 iPadOS 上,在 PWA 窗口中调用 open() 会返回 null,并且不会打开窗口。在 Android 上打开新窗口会为网址创建一个新的应用内浏览器(即使该网址在 PWA 的范围内),这通常不会触发外部浏览体验。

窗口标题

由于浏览器标签页中的空间有限,<title> 元素主要用于搜索引擎优化 (SEO) 目的。在 PWA 中从浏览器移到窗口时,所有标题栏空间都可供您使用。

您可以定义标题栏的内容:

  • 在 HTML <title> 元素中静态存在。
  • 随时动态更改 document.title 字符串属性。

在桌面 PWA 上,标题是必不可少的,会用在窗口的标题栏中,有时还会用在任务管理器或多任务选择中。如果您提供的是单页应用,则可能需要针对每条路线更新标题。

标签页模式

一项实验性功能(称为标签页模式)可让您的 PWA 采用类似于网络浏览器的基于标签页的设计。在这种情况下,用户可以从同一 PWA 打开多个标签页,但所有标签页都绑定在同一个操作系统窗口中,如以下视频所示:

如需详细了解这项实验性功能,请参阅 PWA 的标签式应用模式

窗口控件叠加层

我们已经提到,您可以通过定义 <title> 元素或 document.title 属性的值来更改窗口的标题。但始终是字符串值。如果我们可以使用 HTML、CSS 和图片来按照自己的意愿设计标题栏,结果会怎样? 这正是“窗口控件叠加层”的用武之地,它是 Microsoft Edge 和 Google Chrome 桌面版 PWA 中的一项全新实验性功能。

如需详细了解此功能,请参阅自定义 PWA 标题栏的窗口控件叠加层

通过窗口控件叠加,您可以在标题栏中呈现内容。

窗口管理

如果有多个屏幕,用户会希望充分利用可用的空间。例如:

  • 多窗口图形编辑器 à la Gimp 可将各种编辑工具放置在准确定位的窗口中。
  • 虚拟交易公司可通过多个窗口显示市场趋势,其中任一窗口均可在全屏模式下查看。
  • 幻灯片应用可以在内部主屏幕中显示演讲者备注,并在外部投影仪上显示演示文稿。

借助 Window Management API,PWA 能够执行此类操作,甚至更多。

正在获取屏幕详情

Window Management API 添加了一个新方法 window.getScreenDetails(),该方法可返回一个对象,其中包含以不可变的附加屏幕数组的形式提供屏幕。此外,还有一个可从 ScreenDetails.currentScreen 访问的有效对象,与当前的 window.screen 相对应。

screens 数组发生更改时,返回的对象还会触发 screenschange 事件。(更改单个屏幕上的属性时不会出现这种情况。)当各个屏幕(window.screenscreens 数组中的屏幕)的属性发生变化时,也会触发 change 事件。

// Request an object with a screen objects
const screenDetails = await window.getScreenDetails();
screenDetails.screens[0].isPrimary;  // e.g. true
screenDetails.screens[0].isInternal;  // e.g. true
screenDetails.screens[0].pointerTypes;  // e.g. ["touch"]
screenDetails.screens[0].label;  // e.g. 'Samsung Electric Company 28"'

// Access the live object corresponding to the current `window.screen`.
// The object is updated on cross-screen window placements or device changes.
screenDetails.currentScreen;
screenDetails.addEventListener('screenschange', function() {
 // NOTE: Does not fire on changes to attributes of individual screens.
  const screenCount = screenDetails.screens.length;
  const currentScreen screenDetails.currentScreen.id;
});

如果用户或操作系统将 PWA 的窗口从一个屏幕移动到另一个屏幕,系统也会从屏幕详细信息对象触发 currentscreenchange 事件

屏幕唤醒锁定

想象一下:您在厨房里,使用平板电脑跟着一份食谱烹饪。你的食材刚刚准备好了。您的双手一团糟,为了搞定设备,您不得不回头看下一步。惨了!屏幕变黑了!Screen Wake Lock API 非常适合您,可让 PWA 阻止屏幕变暗、休眠或锁定,从而使用户可以放心地停止、启动、离开和返回屏幕。

// Request a screen wake lock
const wakeLock = await navigator.wakeLock.request();

// Listen for wake lock release
wakeLock.addEventListener('release', () => {
 console.log(`Screen Wake Lock released: ${wakeLock.released}`);
});
// Manually release the wake lock
wakeLock.release();

虚拟键盘

触控设备(如手机和平板电脑)会提供一个虚拟屏幕键盘,这样,当 PWA 的表单元素获得焦点时,用户就可以输入内容了。

借助 Virtual 键盘 API,您的 PWA 现在可以使用 navigator.virtualKeyboard 接口在兼容平台上更好地控制键盘,包括:

  • 使用函数 navigator.virtualKeyboard.show()navigator.virtualKeyboard.hide() 显示和隐藏虚拟键盘。
  • navigator.virtualKeyboard.overlaysContent 设为 true,以告知浏览器您会自行关闭虚拟键盘。
  • 通过 navigator.virtualKeyboard 的事件 geometrychange 获知键盘何时出现和消失。
  • 使用 virtualkeyboardpolicy HTML 属性设置有关修改主机元素(使用 contenteditable)的虚拟键盘政策。借助政策,您可以决定是希望由浏览器使用 auto 值自动处理虚拟键盘,还是由您的脚本使用 manual 值处理虚拟键盘。
  • 使用 CSS 环境变量获取有关虚拟键盘外观的信息,例如 keyboard-inset-heightkeyboard-inset-top

如需详细了解此 API,请参阅 Virtual 键盘 API 实现完全控制

资源