Popup 与 Overlay
Popup 和 Overlay 用于显示脱离正常布局流的内容,例如下拉框、日期选择、右键菜单、通知、抽屉和模态框。
典型场景
RenderComboBox的下拉选项。RenderDatePicker的日期面板。RenderColorPicker的颜色面板。ContextMenuManager的右键菜单。NotificationManager的 toast 通知。RenderModal的模态框。RenderDrawer的抽屉。
PopupManager
PopupManager 负责管理当前弹层上下文、绘制请求和关闭流程。业务通常不直接操作底层 Popup,而是使用具体组件。
自定义弹层需要明确:
- 锚点是谁。
- 如何计算弹层位置。
- 点击外部是否关闭。
- Escape 是否关闭。
- 焦点如何进入和恢复。
- 关闭时如何释放资源。
局部 OverlayHost
RenderOverlayHost 是布局组件,不通过 PopupManager 挂到全局弹层。它把底层内容和覆盖层内容都放在同一棵 render tree 中,适合当前工作区内的应用中心、局部选择器、局部阻断面板。
选择边界:
- 浮层需要跟随某个输入控件或右键位置时,使用 popup / popover / context menu。
- 浮层只属于当前布局区域,且希望遮罩限制在这个区域内时,使用
RenderOverlayHost。 - 浮层需要全局模态、通知层级或跨工作区显示时,使用 modal / notification / drawer 等组件。
- 浮层属于开发者工具、请求日志、布局检查器这类宿主工具区,并且不应被业务 modal/loading 遮挡时,使用
AppOverlayService.showDockWindow()。
宿主停靠窗口
AppOverlayService.showDockWindow() 会把 RenderWindow 作为 runtime 级 root 停靠在主内容区左侧、右侧或底部。停靠窗口不属于主窗口的 owned windows;主内容 viewport 会被停靠区域挤压,普通 popup、modal、loading 只覆盖主内容区。停靠窗口标题栏提供左侧/右侧/底部/浮动切换,并且相邻主内容的边缘可以拖拽调整尺寸。同一 side 上的多个停靠窗口会共享该 side 的厚度,并沿垂直或水平方向分段显示,避免互相覆盖。
宿主停靠窗口适合:
- Layout Inspector。
- Runtime Diagnostics。
- 请求日志、网络面板、状态监控面板。
它不适合业务流程中的详情抽屉、选择弹窗或表单弹窗;这些仍应使用 Drawer、Modal、Popover、Popup 或局部 RenderOverlayHost。
锚点定位
锚点弹层需要跟随触发控件移动。当页面滚动、布局变化或窗口尺寸变化时,弹层位置必须重新计算。
下拉、日期选择、颜色选择和查询选择都属于锚点弹层。
Overlay 层级
不同弹层有不同层级:
- 普通 popup。
- modal overlay。
- tooltip。
- notification。
层级设计要避免 tooltip 被 modal 遮挡关系弄乱,也要避免非交互层拦截底层事件。
生命周期
弹层关闭后应释放:
- 子组件。
- 输入会话。
- 定时器。
- 事件订阅。
- 临时上下文。
如果弹层内容很重,不应在未显示时长期持有完整组件树。
性能原则
- 大列表下拉应限制最大高度或虚拟化。
- popup 重定位应基于锚点矩形,不应全量布局页面。
- 通知高频出现时要合并或限流。
- 关闭弹层必须断开引用,避免内存泄露。