组件/设计工程概念手册/浮层按打开顺序取号与吸顶分割边界

浮层按打开顺序取号与吸顶分割边界

不靠写死的大数字排先后:TuffEx 的浮层从同一个计数器按打开顺序取 z-index,抽屉先把计数抬到 10000;吸顶条用 1px 细线而非投影。

设计理念

浮层按打开顺序取号与吸顶分割边界

在专业桌面端应用中,随意堆砌 z-index 会导致严重的视图穿透与遮挡冲突。TuffEx 不给浮层分固定的层级档位,而是让它们按打开顺序,从同一个计数器取号。

消除 z-index 军备竞赛

传统前端工程遇到图层遮挡时,往往随意写下 z-index: 9999 或 99999。这会导致:

  • 下拉菜单穿透系统弹窗。
  • 气泡提示被吸顶栏截断。
  • 多 Agent 协同编写业务模块时层级彻底失控。

固定的层级档位也解决不了这个问题:弹窗里打开的下拉菜单必须盖住弹窗,抽屉里打开的弹窗又必须盖住抽屉。谁该在上面,取决于打开的先后,而不是组件的种类。

按打开顺序取号

TuffEx 的浮层在打开时向 z-index 分配器取下一个号(next(),即当前值加 1),所以后打开的总是盖在先打开的上面:

  • 取号的组件:TxModal;基于 TxBaseAnchor 的浮层,如 TxPopover、TxTooltip、TxSelect、TxDropdownMenu、TxContextMenu;以及 TxCommandPalette、TxFlipOverlay、TxPicker、TxLoadingOverlay 和各类 Dialog。TxToastHost 在每次调用 toast() 时取号。
  • 起点:计数器从 2000 起步(DEFAULT_Z_INDEX_SEED),第一个浮层拿到 2001。不带参数调用 refresh() 时,会改读 CSS 变量 --tx-index-popper,取两者中较大的那个。
  • 抽屉:TxDrawer 打开时先 refresh(10000),把计数抬到至少 10000 再取号,所以第一个抽屉是 10001,在抽屉里打开的浮层从 10002 往上排。传了 z-index 时直接用这个值,并把计数抬到至少这个值。
  • 只增不减:关闭浮层不会退号,下一个浮层照样取更大的号。
  • 按应用隔离:app.use(Tuffex) 时为这个应用建一个分配器,没有 Vue 应用的调用方共用模块级的那一个。

业务代码要做自己的浮层时,同样用 useZIndexAllocator() 取号,不要写死数字。

示例加载中...

variables.scss 里另有 --tx-index-normal: 1、--tx-index-top: 1000、--tx-index-popper: 2000 三个令牌。--tx-index-popper 除了作分配器的起点,也是 TxVersionCapsule 面板的层级;--tx-index-top 给 TxMotion 的全局进度条用,让它压在所有浮层之下;--tx-index-normal 组件没有用到。TxMotion 的全局指针层是例外,固定为 2147483647:它要跟着指针盖过抽屉和对话框,而分配器的号没有上限。组件内部写死的 z-index 大多是 −1 到 10 的小数值,只在组件自己的层叠上下文里排先后。

吸顶条使用 1px 细线而非投影

当表格表头或操作条固定在顶部、下方内容滚动经过时,禁止使用弥散投影(Drop Shadow)作为分割。

// 错误写法:阴影让吸顶条漂浮在半空,破坏了滚入内容首行的清晰度
.sticky-bar { box-shadow: 0 4px 12px rgba(0,0,0,0.15); }

// 正确写法:使用 1px 细线形成清脆物理截断
.sticky-bar {
  border-bottom: 1px solid var(--tx-border-color);
  background-color: var(--tx-bg-color); // 必须是不透明实底
}

吸顶元素是视窗的物理闸门,而非空中悬浮物。1px 细线能明确界定滚出边界,保持整体版面的严谨秩序。

示例加载中...