应用网域
为了演示将迷你应用编程方式应用于 Web 应用,我需要一个小巧但足够完整的应用想法。高强度间歇训练 (HIIT) 是一种心血管锻炼策略,将短时间的高强度无氧运动与强度较低的恢复期交替进行。许多 HIIT 训练都使用 HIIT 计时器,例如 The Body Coach TV YouTube 频道中的这项 30 分钟在线课程。
HIIT Time 示例应用
在本章中,我构建了一个此类 HIIT 计时器应用的基本示例,并将其命名为“HIIT Time”,以便用户定义和管理各种计时器(始终由高强度和低强度间歇组成),然后为训练时段选择其中一个计时器。这是一个自适应应用,包含一个导航栏、一个标签页栏和三个页面:
- 锻炼:锻炼期间的活动页面。该组件允许用户选择一个计时器,并且具有三个进度环:集合数、活动期和静息期。
- 计时器:管理现有计时器,并允许用户创建新计时器。
- 偏好设置:允许切换音效和语音输出,以及选择语言和主题。
以下屏幕截图展示了该应用的界面。
应用结构
如上所述,该应用由一个导航栏、一个标签页栏以及三个以网格形式排列的页面组成。导航栏和标签栏以 iframe 的形式实现,中间有一个 <div>
容器,另外还有三个用于网页的 iframe,其中一个始终可见,并且取决于标签栏中的有效选择。最后一个指向 about:blank
的 iframe 用于动态创建的应用内页面,这些页面对于修改现有计时器或创建新计时器至关重要。我将这种模式称为多页单页应用 (MPSPA)。
基于组件的 lit-html 标记
每个页面的结构都以 lit-html 基架的形式实现,该基架会在运行时进行动态评估。如需了解 lit-html 的背景信息,请参阅以下内容:它是一个高效、富有表现力且可扩展的 JavaScript HTML 模板库。
通过直接在 HTML 文件中使用它,心理编程模型直接面向输出。作为程序员,您需要编写最终输出的模板,然后 lit-html 会根据您的数据动态填充空白并连接事件监听器。该应用使用第三方自定义元素(例如 Shoelace 的 <sl-progress-ring>
)或名为 <human-duration>
的自实现自定义元素。由于自定义元素具有声明式 API(例如进度圈的 percentage
属性),因此它们可以与 lit-html 很好地协同工作,如以下列表所示。
<div>
<button class="start" @click="${eventHandlers.start}" type="button">
${strings.START}
</button>
<button class="pause" @click="${eventHandlers.pause}" type="button">
${strings.PAUSE}
</button>
<button class="reset" @click="${eventHandlers.reset}" type="button">
${strings.RESET}
</button>
</div>
<div class="progress-rings">
<sl-progress-ring
class="sets"
percentage="${Math.floor(data.sets/data.activeTimer.sets*100)}"
>
<div class="progress-ring-caption">
<span>${strings.SETS}</span>
<span>${data.sets}</span>
</div>
</sl-progress-ring>
</div>
编程模型
每个页面都有一个对应的 Page
类,该类通过提供事件处理脚本的实现并为每个页面提供数据,为 lit-html 标记注入活力。此类还支持 onShow()
、onHide()
、onLoad()
和 onUnload()
等生命周期方法。页面可以访问数据存储区,该数据存储区可共享选择性保留的每个页面状态和全局状态。所有字符串均集中管理,因此内置了国际化功能。
浏览器基本上可以免费处理路由,因为应用只需切换 iframe 的公开范围,并针对动态创建的页面更改占位符 iframe 的 src
属性即可。以下示例展示了用于关闭动态创建的网页的代码。
import Page from '../page.js';
const page = new Page({
eventHandlers: {
back: (e) => {
e.preventDefault();
window.top.history.back();
},
},
});
样式
页面的样式设置是在每个页面自己的 CSS 文件中进行的。这意味着,元素通常可以直接通过其元素名称进行访问,因为不会与其他页面发生冲突。每个页面都会添加全局样式,因此无需重复声明 font-family
或 box-sizing
等中心设置。您还可以在此处定义主题和深色模式选项。以下列表显示了“偏好设置”页面的规则,该页面会在网格中排列各种表单元素。
main {
max-width: 600px;
}
form {
display: grid;
grid-template-columns: auto 1fr;
grid-gap: 0.5rem;
margin-block-end: 1rem;
}
label {
text-align: end;
grid-column: 1 / 2;
}
input,
select {
grid-column: 2 / 3;
}
屏幕唤醒锁定
在锻炼期间,屏幕不应关闭。在支持此功能的浏览器中,HIIT Time 通过屏幕唤醒锁定实现此目的。以下代码段展示了具体方法。
if ('wakeLock' in navigator) {
const requestWakeLock = async () => {
try {
page.shared.wakeLock = await navigator.wakeLock.request('screen');
page.shared.wakeLock.addEventListener('release', () => {
// Nothing.
});
} catch (err) {
console.error(`${err.name}, ${err.message}`);
}
};
// Request a screen wake lock…
await requestWakeLock();
// …and re-request it when the page becomes visible.
document.addEventListener('visibilitychange', async () => {
if (
page.shared.wakeLock !== null &&
document.visibilityState === 'visible'
) {
await requestWakeLock();
}
});
}
测试应用
HIIT Time 应用可在 GitHub 上找到。您可以在新窗口中播放该演示,也可以直接在下方的 iframe 嵌入中(模拟移动设备)进行播放。
致谢
本文由 Joe Medley、Kayce Basques、Milica Mihajlija、Alan Kent 和 Keith Gu 审核。