保留状态的编辑器
通过两个真实微应用体验窗口与 PiP、拖放、过渡和 keep-alive。
打开移动中的应用。React 保留编辑器草稿,Vue 管理收到笔记的收件箱。WU 在同一文档中使用独立的 Shadow DOM 根挂载两个应用,并协调它们的交互。示例使用构建中包含的 WU Framework 4.0.0。
四项任务,一个场景
| 操作 | 观察内容 |
|---|---|
| 输入并发送笔记 | 将卡片拖放到 Vue 或使用发送按钮。完成类型和权限检查后,收件箱会收到数据副本。 |
| 隐藏并显示编辑器 | 草稿和 React 实例保持不变,不会重新执行挂载。 |
| 改变面板布局 | 过渡动画改变布局,输入和接收笔记仍可正常使用。 |
| 移出并返回编辑器 | 打开窗口,在其中输入,然后返回。同一组节点会移回宿主。浏览器提供该 API 时才启用 PiP。 |
每个应用负责什么
Shell 拥有一个 new WuCore() 实例,注册两个应用并授予权限。React 负责草稿并提供 docs.note 类型;Vue 验证并接收该类型。可视控件是 Lit Custom Elements。context.wu 上下文在发送或接收数据时保留各微应用的权限身份。
以下代码片段在初始化运行时并挂载应用后执行。runtime 是 Shell 实例。要复现完整启动过程,请查看本指南末尾的源代码。
窗口与画中画
// Prepare the optional subsystem before the user clicks.
await runtime.windowsReady();
openButton.addEventListener('click', async () => {
try {
await runtime.detach('interaction-editor', {
window: 'popup', width: 560, height: 520,
});
status.textContent = String(runtime.isDetached('interaction-editor'));
} catch (error) {
status.textContent = error.message;
}
});
returnButton.addEventListener('click', () => {
runtime.attach('interaction-editor');
});
请先创建 openButton、returnButton 和 status。对于 PiP,请检查支持情况后,在点击处理中使用 window: "pip"。windowOf(name) 可查询当前窗口。关闭窗口会将应用移回页面;离开此场景则会卸载应用。模块继续在原始页面中执行,编辑器保留相同的节点和状态。
通过鼠标或键盘进行类型化传递
// Sending app: its manifest requests drag.offer:docs.note.
const stopOffer = await context.wu.drag.offer(card, {
type: 'docs.note',
payload: () => ({ text: readDraft() }),
});
// The send button uses the same permission and validation path.
await context.wu.drag.deliver('docs.note', { text: readDraft() }, {
to: 'interaction-board',
});
// Receiving app: its manifest requests drag.accept:docs.note.
const stopAccept = await context.wu.drop.accept(inbox, {
type: 'docs.note',
validate(note) {
if (!note || typeof note.text !== 'string' || !note.text.trim()) {
throw new TypeError('A non-empty note is required');
}
return note;
},
onDrop: note => addToInbox(note),
});
该片段展示了两端逻辑:提供和发送属于编辑器,接收属于收件箱。请将 card、inbox、readDraft 和 addToInbox 替换为各应用中的引用。宿主必须向对应应用授予两项权限。保留 stopOffer 和 stopAccept,并在卸载时调用。
保留状态并改变布局
await runtime.unmount('interaction-editor', { keepAlive: true });
await runtime.show('interaction-editor');
// panelA and panelB have stable data-wu-vt keys inside workspace.
const animation = runtime.transition(() => {
workspace.classList.toggle('stacked');
}, { root: workspace, duration: 320 });
await animation.updateCallbackDone;
await animation.finished;
定义 stacked 类来将面板排列为一列,并向 WU 需要测量的元素添加 data-wu-vt。隐藏会保留实例,但不会自动停止你创建的定时器或连接。过渡会遵循减少动态效果设置。要完全移除此场景,请调用 runtime.destroy() 并释放宿主的外部资源。
源码与参考
官方仓库中的完整示例包含清单和构建说明。Lit 控件属于同一项目。请克隆完整仓库并按照 README 运行;下方的三个下载文件展示了集成代码和控制器。
阅读 Shell 控制器、React 编辑器和 Vue 收件箱。这些是用于构建示例的源文件。有关签名、权限和错误,请查看拖放、窗口与焦点以及生命周期。
PiP 支持取决于浏览器;Chrome 文档介绍了用户手势和窗口生命周期。发送按钮允许读者无需拖动即可完成任务,符合 WCAG 拖动操作准则。