修复虚拟列表卡片区空白:页面高度按父级实测
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust smoke (pull_request) Has been cancelled
Project CI / AI game creator shell Rust crates (pull_request) Has been cancelled
Project CI / Backend tests (pull_request) Has been cancelled
Project CI / Native shell tests (pull_request) Has been cancelled
Project CI / Frontend tests (pull_request) Has been cancelled
Project CI / Repository checks (pull_request) Has been cancelled
Project CI / AI game creator shell web tests (pull_request) Has been cancelled

- 页面根节点高度改为内联写入父级 .launcher-main 的实测高度:外壳的 .launcher-main > .platform-theme { height:100% } 特异性高于 Tailwind,且该百分比在 min-height:100vh 链上是不定高,页面退化成内容高度后虚拟网格视口为 0(卡片区整片空白);100vh 又比舞台高一个标题栏会裁掉底部
- 技术方案补页面高度契约说明
- 真机复测(1000 条假数据):可视区 16 张卡、进入页面后 23ms 出现卡片、搜索到空态 22ms、清空搜索回全量 22ms;WebView2 组工作集 487MB(修复前 4.2-4.6GB)
This commit is contained in:
kdletters
2026-09-17 17:27:30 +08:00
parent 13d272c2d4
commit 5a219e53a5
2 changed files with 36 additions and 1 deletions
@@ -135,6 +135,8 @@ export default function TemplateLibraryView({
const gridRef = useRef<FixedSizeGrid>(null);
const viewportRef = useRef<HTMLDivElement | null>(null);
const sectionRef = useRef<HTMLElement | null>(null);
const [sectionHeight, setSectionHeight] = useState<number | null>(null);
const [viewportSize, setViewportSize] = useState({ width: 0, height: 0 });
const showEmptyLibrary = status === 'ready' && templates.length === 0;
@@ -142,6 +144,36 @@ export default function TemplateLibraryView({
status === 'ready' && templates.length > 0 && visibleTemplates.length === 0;
const showGrid = status === 'ready' && visibleTemplates.length > 0;
/**
* 页面高度按**父级实测高度**定,不用百分比也不用 100vh。
*
* 外壳样式 `.launcher-main > .platform-theme { height: 100% }` 特异性高于 Tailwind
* 工具类,而它的百分比在 `.launcher-shell { min-height: 100vh }` 这条链上是不定高,
* 页面会退化成内容高度(虚拟网格视口高度 0、卡片区空白);`100vh` 又比真实舞台高
* 一个标题栏(窗口 100vh=800、舞台 750),底部会被裁掉。这里直接量父级。
*/
useEffect(() => {
const section = sectionRef.current;
const parent = section?.parentElement;
if (!section || !parent) {
return;
}
const apply = () => {
const height = Math.round(parent.getBoundingClientRect().height);
if (height > 0) {
setSectionHeight((current) => (current === height ? current : height));
}
};
apply();
if (typeof ResizeObserver === 'undefined') {
window.addEventListener('resize', apply);
return () => window.removeEventListener('resize', apply);
}
const observer = new ResizeObserver(apply);
observer.observe(parent);
return () => observer.disconnect();
}, []);
useEffect(() => {
const element = viewportRef.current;
if (!element) {
@@ -216,7 +248,9 @@ export default function TemplateLibraryView({
return (
<section
className="platform-theme platform-theme--light flex h-full min-h-0 w-full flex-col gap-3.5 overflow-hidden px-6 pb-5 pt-5 max-[760px]:px-4"
ref={sectionRef}
style={sectionHeight ? { height: `${sectionHeight}px` } : undefined}
className="platform-theme platform-theme--light flex min-h-0 w-full flex-col gap-3.5 overflow-hidden px-6 pb-5 pt-5 max-[760px]:px-4"
aria-label="模板库"
>
<header className="flex flex-wrap items-center gap-3">
@@ -102,6 +102,7 @@ AGC_TEMPLATE_LIBRARY_SYNTHETIC_COUNT=300 AGC_DEV_CARGO_FEATURES=template-library
- 列表改用 workspace 里已有的 `react-window@1.8.11``FixedSizeGrid``react-arborist` 已在用同一版本,不引入新包;类型来自 devDependency `@types/react-window`)。
- 布局契约收在纯函数 `templateLibraryGrid.ts`(单测覆盖):列数 = `floor((容器宽 + gap) / (最小卡宽 + gap))`、列宽 = 容器宽 / 列数、行高 = `卡片宽 × 9/16 + 文字区 150 + gap``buildTemplateRows` 按行切分并在行尾补 `null` 占位。
- 卡片抽成 `TemplateCard``memo`),网格只渲染可视行 + 2 行 overscan;筛选条件(关键词/标签/运行时/仅看已下载)变化时把滚动位置复位到顶部,避免"从筛选切回全量后停在空白处"。
- **页面高度契约**:页面根节点的高度按**父级 `.launcher-main` 的实测高度**内联设置,既不用百分比也不用 `100vh`。原因:外壳样式 `.launcher-main > .platform-theme { height: 100% }` 特异性高于 Tailwind 工具类,而这条百分比在 `.launcher-shell { min-height: 100vh }` 链路上是不定高,页面会退化成内容高度(虚拟网格视口高度 0、卡片区整片空白);`100vh` 又比真实舞台高一个标题栏高度(窗口 100vh=800 / 舞台 750),底部会被裁掉。
- 筛选区(运行时/标签)改成可独立滚动的区块(`max-h-[24vh]`),标签数量随库量增长时不再把卡片区挤出窗口。
- 回归:`templateLibraryGrid.test.ts` 覆盖列数/行高/行数/切行;页面测试用固定视口断言「1000 条只渲染 ≤ 40 张卡片,滚动高度仍按 250 行计算」。