Tree title 溢出检测改为按需测量(DES-132)
版本: 0.4.0 · 类型: ✨ 新功能
关联 issue:DES-132(DES-75 Tree 父 issue 下子任务)
问题
web4 左侧文件夹列表(FolderTreeAdapter)在文件夹数达到几百时出现明显卡顿。
DOM 行本身不复杂,根因不在节点数量,而在每个 TreeNode 挂载时 useTitleOverflow
都会同步执行一次 measureTitleOverflow:
titleEl.clientWidth // 读布局
host.appendChild(clone) // 写 DOM
clone.offsetWidth // 读布局 → 强制同步 reflow
clone.remove() // 写 DOM
成百上千个节点同时挂载时,这种「写→读→写→读」交替会触发等量的强制同步 reflow
(布局抖动 / layout thrashing),浏览器无法批处理,是主要卡顿来源。叠加每个节点常驻
一个 ResizeObserver,进一步放大开销。
改动文件
src/components/Tree/Tree.tsxsrc/components/Tree/__tests__/Tree.test.tsxsrc/components/Tree/__tests__/Tree.ct.spec.tsx
改动内容
useTitleOverflow由「挂载即测 + 每节点常驻 ResizeObserver」改为按需测量: 返回[overflowed, measure],仅在指针进入 / 聚焦该行时调用measure测一次, 同一 title 已测过则跳过。挂载期的逐节点 reflow 降为 0。TreeNode行容器新增onPointerEnter/onFocus触发measure(onFocus保留键盘可达性,聚焦行同样能触发 tooltip 包裹)。- tooltip 本就只在 hover / focus 时才需要,测量推迟到该时刻对用户无感知。
行为变化
(契约更新)
- 超长 title 不再在挂载时立即包成 Tooltip trigger,而是在首次指针进入 / 聚焦该行后包裹。
- 移除 ResizeObserver 后,容器宽度变化(如拖拽侧栏)不再自动重测,stale 状态会在 下次指针进入 / 聚焦该行时刷新。
- 测试已同步:
Tree.test.tsx/Tree.ct.spec.tsx的 tooltip 断言改为先触发 pointer enter / hover 再断言data-state。
备注
本次为节点级优化,降低每节点固定成本,节点总数仍是线性。几百~一两千节点场景可显著缓解; 若后续出现几千节点的极端场景,需进一步引入虚拟列表(拍平 + 视口渲染)根治。