跳到主要内容

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.tsx
  • src/components/Tree/__tests__/Tree.test.tsx
  • src/components/Tree/__tests__/Tree.ct.spec.tsx

改动内容

  • useTitleOverflow 由「挂载即测 + 每节点常驻 ResizeObserver」改为按需测量: 返回 [overflowed, measure],仅在指针进入 / 聚焦该行时调用 measure 测一次, 同一 title 已测过则跳过。挂载期的逐节点 reflow 降为 0。
  • TreeNode 行容器新增 onPointerEnter / onFocus 触发 measureonFocus 保留键盘可达性,聚焦行同样能触发 tooltip 包裹)。
  • tooltip 本就只在 hover / focus 时才需要,测量推迟到该时刻对用户无感知。

行为变化

(契约更新)

  • 超长 title 不再在挂载时立即包成 Tooltip trigger,而是在首次指针进入 / 聚焦该行后包裹。
  • 移除 ResizeObserver 后,容器宽度变化(如拖拽侧栏)不再自动重测,stale 状态会在 下次指针进入 / 聚焦该行时刷新。
  • 测试已同步:Tree.test.tsx / Tree.ct.spec.tsx 的 tooltip 断言改为先触发 pointer enter / hover 再断言 data-state

备注

本次为节点级优化,降低每节点固定成本,节点总数仍是线性。几百~一两千节点场景可显著缓解; 若后续出现几千节点的极端场景,需进一步引入虚拟列表(拍平 + 视口渲染)根治。