左侧文件树偶发黑屏,滚动后恢复¶
状态:已修复(虚拟行改 top 定位 + 视口 Resize 同步 scrollOffset + 侧栏只保留 isolate 叠层隔离,去掉全区 transform-gpu 合成层)
影响面:左侧 Vault 文件树(打开/关闭论文、切换标签、树刷新、导入后更易触发)
相关代码:
src/components/sidebar/file-tree/tree-rows-viewport.tsx— 虚拟行用top而非transform: translateYsrc/components/sidebar/file-tree/hooks/use-tree-reveal.ts—useAnimationFrameWithResizeObserver;ResizeObserver 把 DOMscrollTop同步回 virtualizersrc/App.tsx—[data-vault-sidebar]只用isolate(叠层隔离),不再给整个侧栏加transform-gpu合成层- 文档:
docs/frontend/vault-tree.md
1. 问题现象¶
左侧文件树区域偶尔整片变黑 / 空白,像没有绘制;鼠标滚一下或拖动滚动条后内容立刻回来。多在打开/关闭论文、导入或树刷新之后出现。
2. 根因¶
文件树用 @tanstack/react-virtual 窗口化,原先每行:
style={{ transform: `translateY(${vi.start}px)` }}
在 Tauri macOS(WKWebView)上,transform 会把每一行提升为独立合成层。打开论文时中间栏 PDF / EmbedPDF 会制造大量 GPU 层与布局抖动;侧栏这些 transform 层有时不会被正确标脏,直到下一次滚动强制重绘。
叠加第二条路径:Paper Info 面板挂载会缩短树的滚动视口高度。WebKit 可能在不发 scroll 事件的情况下钳制 scrollTop,而 virtualizer 仍持有旧的 scrollOffset,getVirtualItems() 算出空窗口,表现同样是侧栏空白,滚动后才对齐。
复发(#607):首轮修复在 aside[data-vault-sidebar] 上加了 transform-gpu,却把整条侧栏提升成单个合成层。打开论文 / 切换标签 / 导入时中间栏 PDF 制造大量 GPU 层,WKWebView 会把这条整区层留在「已合成但未标脏」的状态——表现仍是整片变黑、滚动后恢复。此时行已用 top 定位(无逐行层),整区合成层不再必要,反而是复发源。
3. 修复¶
- 行定位改
top:不再用translateY,减少逐行合成层,避开 WKWebView 脏区漏标。 - 视口 Resize 同步偏移:观察树滚动容器,若 DOM
scrollTop与 virtualizer 偏移不一致则scrollToOffset;并开启useAnimationFrameWithResizeObserver,让 React 提交后再量几何。 - 只做叠层隔离,不做整区合成层:
aside[data-vault-sidebar]只保留isolate(创建 stacking context),去掉transform-gpu。行不再有transform,无需再靠整区 GPU 层与 PDF 隔离;避免整区层被 WKWebView 漏标而整片变黑(#607)。
4. 验证注意¶
该问题依赖 WKWebView 合成行为,纯浏览器 pnpm dev 不一定复现。回归时用 pnpm tauri dev:打开带 PDF 的论文、切换标签、导入后观察左侧树是否仍会黑屏;故意滚一下应不再是「唯一恢复手段」。
607 的修复(去掉整区 transform-gpu)必须用 pnpm tauri dev 在 macOS WKWebView 上验证——Chromium 下侧栏本就不会出现该合成层漏标,无法作为回归证据。验证清单:打开论文 / 切换标签 / 导入后,左侧树应直接完整绘制,无需滚动;同时确认侧栏与 PDF 之间没有出现新的层叠/穿透问题。¶
5. 后续加固(#738)¶
打开另一篇论文笔记(Notes 面板原位替换)时仍能复现:openTab 先插入 paperMeta: null 的占位 tab,Paper Info 因此卸载 → 树视口变高;资源加载后 Paper Info 重新挂载 → 视口变矮。两次高度变化 + remapPanel 的 dock 布局变更叠加,WebKit 静默钳制 scrollTop,virtualizer 空窗口,表现为被点的树行消失、滑动才回来。
- Paper Info 不再闪断:
vault-sidebar.tsx在当前 tab 尚未加载出paperMeta时,先用活动路径(论文目录或论文内文件)+ 文件树 / catalog 反查所属论文,保持 Paper Info 挂载、树视口高度不变。覆盖打开论文与打开笔记两条路径。 - 空窗口自愈:
use-tree-reveal.ts增加 watchdog——行集合或选中项变化、Resize 同步后,若flatRows非空但getVirtualItems()为空,则把 DOMscrollTop(必要时先钳到最大滚动范围)写回 virtualizer,无需用户滚动即可恢复。仅补渲染窗口,不改变正常滚动行为。