From 0619903e3f1594258ceb7537964b5ec4b94bfefb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=BE=B7=E5=AE=87?= Date: Wed, 30 Sep 2026 13:24:55 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=B8=B8=E7=8E=A9=E9=A1=B5?= =?UTF-8?q?=E9=9D=A2=E6=9D=BF=E4=B8=8D=E6=BB=9A=E5=8A=A8=E8=A7=84=E5=88=99?= =?UTF-8?q?=E8=A2=AB=20workbench=20=E7=A5=96=E5=85=88=E8=A7=84=E5=88=99?= =?UTF-8?q?=E5=8E=8B=E6=8E=89=20-=20.platform-tab-panel--game-play=20?= =?UTF-8?q?=E8=A6=86=E7=9B=96=E5=B8=A6=E4=B8=8A=20.platform-desktop-shell-?= =?UTF-8?q?-workbench=20=E7=A5=96=E5=85=88=EF=BC=8C=E5=8E=8B=E8=BF=87=20ov?= =?UTF-8?q?erflow:=20auto=20-=20E2E=20=E6=B8=B8=E7=8E=A9=E9=A1=B5=E6=96=AD?= =?UTF-8?q?=E8=A8=80=E8=A1=A5=E6=95=B4=E9=A1=B5=E4=B8=8E=E9=9D=A2=E6=9D=BF?= =?UTF-8?q?=E7=9A=84=E6=A8=AA=E5=90=91=E6=BA=A2=E5=87=BA=E6=B5=8B=E9=87=8F?= =?UTF-8?q?=EF=BC=8C=E9=81=BF=E5=85=8D=E9=9D=A2=E6=9D=BF=20overflow-x:=20h?= =?UTF-8?q?idden=20=E9=9D=99=E9=BB=98=E8=A3=81=E5=88=87=E6=BC=8F=E6=A3=80?= =?UTF-8?q?=20-=20=E4=BF=AE=E6=AD=A3=20E2E=20=E6=8E=A2=E9=92=88=E9=87=8C?= =?UTF-8?q?=E9=87=8D=E5=A4=8D=E7=9A=84=20panelOverflowY=20=E9=94=AE?= =?UTF-8?q?=E5=90=8D=EF=BC=8C=E6=8B=86=E6=88=90=20panelOverflowY=20?= =?UTF-8?q?=E4=B8=8E=20panelOverflowStyle=20-=20=E5=90=8C=E6=AD=A5?= =?UTF-8?q?=E9=87=8C=E7=A8=8B=E7=A2=91=E6=96=87=E6=A1=A3=E4=B8=8E=20pitfal?= =?UTF-8?q?ls=20=E5=90=8C=E6=97=A5=E6=9D=A1=E7=9B=AE=EF=BC=88=E5=8D=95?= =?UTF-8?q?=E7=B1=BB=E5=90=8D=E8=A6=86=E7=9B=96=E8=A2=AB=E7=A5=96=E5=85=88?= =?UTF-8?q?=E8=A7=84=E5=88=99=E5=8E=8B=E6=8E=89=E3=80=81=E5=AE=88=E5=8D=AB?= =?UTF-8?q?=E5=AE=9E=E9=99=85=E4=B8=BA=E7=A9=BA=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...‹碑】游戏分发目录详情与在线游玩-2026-09-18.md | 3 ++- docs/project-memory/shared-memory/pitfalls.md | 8 +++++++ scripts/check-game-distribution-web-e2e.mjs | 21 +++++++++++++------ src/index.css | 10 +++++++-- 4 files changed, 33 insertions(+), 9 deletions(-) diff --git a/docs/project-memory/plans/【里程碑】游戏分发目录详情与在线游玩-2026-09-18.md b/docs/project-memory/plans/【里程碑】游戏分发目录详情与在线游玩-2026-09-18.md index d533dfc83..e3bb04b9a 100644 --- a/docs/project-memory/plans/【里程碑】游戏分发目录详情与在线游玩-2026-09-18.md +++ b/docs/project-memory/plans/【里程碑】游戏分发目录详情与在线游玩-2026-09-18.md @@ -325,9 +325,10 @@ - **广场首屏「立即试玩」不再替用户选中作品**:`src/components/game-distribution/GameGalleryPage.tsx` 原来是 `onClick={() => featuredGame && openDetail(featuredGame.id)}`,点一下等于直接打开第一款游戏的详情。现在按钮只把列表滚进视野(按平台页签面板计算相对偏移,`scrollTo({ behavior: 'smooth' })`,无 `scrollTo` 时退化成直接赋值),不再触发 `onOpenDetail`;`featuredGame` 派生随之退役。回归用例 `GameDistributionPages.test.tsx`「首屏「立即试玩」滚动到列表,而不是打开第一款游戏详情」断言 `onOpenDetail` 未被调用且滚动落在页签面板上。 - **游玩页不再可滚**:移动端此前是整页可滚的半屏播放器。原因是面板仍是 `overflow-auto`,而播放器用 `min-height: calc(100dvh - 8rem)` 撑高页面。现在 `PlatformEntryActiveFlowShell.tsx` 在 `game-play` 舞台给页签容器加 `platform-tab-panel--game-play`(不滚动、去掉多余内边距),`.game-play-page` 改为 `height: 100%; min-height: 0`,播放器 `flex: 1; min-height: 0` 撑满剩余高度;矮视口(`max-height: 26rem`,横屏手机)另给启动面板一套压扁布局,兜底只在极端高度下发生在启动卡片内部,页面与面板本身始终不滚动。启动面板纵向对齐用 `safe center`(`center` 作旧浏览器回退)并把 `overflow-y: auto` 放在基础规则:居中溢出会把顶部标题裁到 `scrollTop = 0` 也够不到的位置,只加内部滚动并不能修掉。回归用例 `PlatformEntryActiveFlowShell.test.tsx`「游玩舞台的页签容器不滚动」「游戏广场等舞台仍保持页签容器滚动」双向锁定。 +- **补齐上面这条的空守卫**:`.platform-tab-panel--game-play { overflow: hidden }` 一开始只有单类名 (0,1,0),被文件更靠后的 `.platform-desktop-shell--workbench .platform-tab-panel { overflow: auto }`((0,2,0))压掉,真实 Chromium 里 `overflow-y` 仍是 `auto`——只是当时内容恰好没溢出,测试与肉眼都没发现。现在覆盖规则带上 workbench 祖先一起写,实测 390x844/360x640/844x390 三档 `overflowY=hidden`、面板与整页横竖都不溢出,广场舞台仍是 `overflow: auto` 且内容可滚。详情见 pitfalls 同日条目。 - **「我的游戏」列表与画廊同口径**:`.my-game-list` 的单列 `auto` 轨道会被 `white-space: nowrap` 的简介顶到内容最小宽度(实测 592px),加上 `.my-game-card` 缺 `min-width: 0`,390/360 宽的手机上卡片超出视口、面板横向可滚且看着不居中。现在改成画廊那套口径(`grid-template-columns: minmax(0, 1fr)`、`.my-game-card { min-width: 0; overflow: hidden }`、标题 `min-width: 0; overflow-wrap: anywhere`);真实 Chromium 夹具在 390/360 下量到轨道=卡片=可视宽、面板横向溢出 0(改前 592px 卡片、横向可滚 230/260px)。 - **页签面板左右留白对齐**:`.platform-tab-panel` 原本写死 `padding-right`(并在移动端与 workbench 两处再压成 0),而它是不分层规则、优先级高于 Tailwind 的 `padding-inline`,导致面板左 12/24px、右 0,列表左右留白 28/16。三处 `padding-right` 删除后左右统一由使用处的 `px-3`/`sm:px-6` 决定:390 下 12/12(列表 28/28)、820 下 24/24(列表 44/44),无 px 类的舞台仍是 0/0;Chromium 夹具实测「我的游戏」与画廊两张页面同时恢复对称,且横向溢出保持 0。 - **广场的「发布游戏」「我的游戏」上移到 hero 右上角**:两个入口原本混在 hero 下方的 `.game-toolbar` 动作区(和搜索框同排),现在提到 `.game-page-actions` 一行、右对齐放在 hero 上方,并留 1.1rem 底部间距;工具栏只保留标题与搜索。未登录或灰度未命中时两者都不渲染,该行随之消失。Chromium 夹具实测 390/360/820 三档都是 `aboveHero=true`、与 hero 间距 18px、右边缘与 hero 对齐。 -- 真机口径的守卫补在现役 E2E 里:`scripts/check-game-distribution-web-e2e.mjs` 的移动端段新增「移动端游玩页不可滚动(面板与整页都不溢出)」,断言 `.platform-tab-panel` 的 `overflow-y` 为 `hidden` 且面板与整页都不溢出(该脚本需真实本地栈,未在本轮执行)。 +- 真机口径的守卫补在现役 E2E 里:`scripts/check-game-distribution-web-e2e.mjs` 的移动端段新增「移动端游玩页不可滚动(面板与整页都不溢出)」,断言 `.platform-tab-panel` 的 `overflow-y` 为 `hidden`,且面板与整页**横竖两轴**都不溢出(面板自身 `overflow-x: hidden`,横向溢出只会被静默裁掉,只量 `scrollHeight` 会漏掉「内容被裁一半」)。(该脚本需要管理员账号发布一款真实游戏,未在本轮执行;同一批数值用 Chromium 直连 dev 栈的 `/games/play?id=…` 量过,见 pitfalls 同日条目。) - **详情页返回按来源回到上一页**:`GameDetailPage` 左上角原来是写死的「返回游戏广场」,并且直接 `setSelectionStage('games')`(等于 push 一条新的 `/games`)。从「我的游戏」点进详情再返回就落到广场,从广场进详情返回也会多压一条重复历史。现在文案简化为「返回」,行为改成优先 `window.history.back()`,由 `ActiveApp` 已有的 `popstate` 同步把舞台还原成真正的来源页(我的游戏 / 广场);游玩页的「返回详情」同样处理,避免详情↔游玩互相 push。协议侧给应用写入的历史条目补了 `__genarrativeAppHistoryDepth`,新增 `hasAppHistoryBackEntry()` 判断「当前条目是应用内导航写入的且存在上一页」;直接打开详情深链、或原生壳里没有可回退条目时,才 `replaceAppHistoryPath` 兜底到广场(游玩页兜底到自己的详情)。回归用例 `activeAppPageRoutes.test.ts` 锁定深度标记语义,`PlatformEntryActiveFlowShell.test.tsx`「游戏详情返回」两条锁定原生返回与深链兜底。 - 验证:`npx vitest run src/components/game-distribution/GameDistributionPages.test.tsx`(21 passed)、`npx vitest run src/components/platform-entry/PlatformEntryActiveFlowShell.test.tsx`(22 passed)、`npx vitest run src/routing/activeAppPageRoutes.test.ts`、`npm run typecheck`、`npx eslint`(五个改动文件)、`npm run check:encoding`、`git diff --check` 全部通过;启动面板的溢出可达性、「我的游戏」移动端横向溢出都用真实 Chromium 静态夹具量过(见 pitfalls 同日条目),详情返回链在真实 Chromium(dev 栈 390x844)实测 `/games`→详情→返回=`/games`、深链直开详情→返回=`/games`、详情→立即玩→返回详情=`/games/detail?id=…`。视觉与真机横竖屏走查仍需人工/截图评审(沿用阶段 C 第 8 条未取证口径)。 diff --git a/docs/project-memory/shared-memory/pitfalls.md b/docs/project-memory/shared-memory/pitfalls.md index 832c9f958..200717b1e 100644 --- a/docs/project-memory/shared-memory/pitfalls.md +++ b/docs/project-memory/shared-memory/pitfalls.md @@ -6125,3 +6125,11 @@ Cocos Creator 根目录由 `package.json.creator.version` 与普通 `assets/` - **处理**:`activeAppPageRoutes` 给应用写入的历史条目补内部深度标记(`push` 时 +1、`replace` 保持),新增 `hasAppHistoryBackEntry()`;详情/游玩页的返回改为「有应用内历史就 `window.history.back()`(`popstate` 已由 `ActiveApp` 同步舞台),否则 `replaceAppHistoryPath` 兜底到广场/详情」。深度标记而不是只看「有没有 state」是必要的:直接打开深链、或原生壳通过 host bridge 补写首条目时,`history.back()` 会直接退出应用。 - **判据**:真实 Chromium(dev 栈 390x844)实测 `/games` → 详情 → 返回 = `/games`;深链直开 `/games/detail?id=…` → 返回 = `/games`;详情 → 立即玩 → 返回详情 = `/games/detail?id=…`。jsdom 侧 `activeAppPageRoutes.test.ts` 锁深度标记语义,`PlatformEntryActiveFlowShell.test.tsx`「游戏详情返回」两条锁原生返回与深链兜底。 - **关联**:`src/routing/activeAppPageRoutes.ts`、`src/ActiveApp.tsx`、`src/components/platform-entry/PlatformEntryActiveFlowShell.tsx`、`src/components/game-distribution/GameDetailPage.tsx`。 + +## 2026-09-30 单类名覆盖被 workbench 祖先规则压掉,游玩页的「不滚动」守卫实际是空的 + +- **现象**:给游玩页面板加的 `.platform-tab-panel--game-play { overflow: hidden }` 看起来生效(类挂上了、单测断言类名也过),但真实 Chromium 里 `getComputedStyle(panel).overflowY` 是 `auto`——守卫没生效,只是当时内容恰好没溢出(`panelOverflowY = 0`),所以肉眼和 jsdom 都看不出来。 +- **根因**:`.platform-desktop-shell--workbench .platform-tab-panel { overflow: auto }`(`src/index.css` 文件末尾附近)特异性是 (0,2,0),而且它在文件里更靠后,把单类名 (0,1,0) 的覆盖压掉了。面板在所有舞台都渲染在这层 workbench 容器里,所以这个覆盖永远轮不到生效。 +- **处理**:覆盖规则带上同样的祖先作用域,`overflow: hidden` 用两个选择器(单类名 + `.platform-desktop-shell--workbench .platform-tab-panel.platform-tab-panel--game-play`)一起写,既压得过 workbench 规则也不依赖文件顺序。 +- **判据**:真实 Chromium(dev 栈 390x844 / 360x640 / 844x390 横屏矮视口)实测 `overflowY=hidden`、面板与整页横竖都不溢出,同时广场舞台仍是 `overflowY=auto` 且内容可滚(689px)。同类问题排查姿势:改 `.platform-tab-panel` 或任何 workbench 内元素的样式,先在浏览器里读 `getComputedStyle`,别只看类名/源码顺序。 +- **关联**:`src/index.css`(`.platform-tab-panel--game-play` 与 `.platform-desktop-shell--workbench .platform-tab-panel`)、`scripts/check-game-distribution-web-e2e.mjs`、`src/components/game-distribution/gameDistribution.css`。 diff --git a/scripts/check-game-distribution-web-e2e.mjs b/scripts/check-game-distribution-web-e2e.mjs index 73a322544..d79fe2231 100644 --- a/scripts/check-game-distribution-web-e2e.mjs +++ b/scripts/check-game-distribution-web-e2e.mjs @@ -523,20 +523,29 @@ async function main() { `startDisabled=${mobileStartDisabled} rotationHint=${rotationHint}`, ); // 游玩页是固定画布:面板必须是 overflow:hidden 且不溢出,整页也不能出现滚动条。 + // 面板自身 `overflow-x: hidden`,横向溢出只会被静默裁掉、不会出滚动条,所以两个方向都要量: + // 只量 scrollHeight 会漏掉「卡片被裁一半」这类横向回归。 const playScroll = await mobilePage.evaluate(() => { const panel = document.querySelector('.platform-tab-panel'); return { - documentOverflow: + documentOverflowY: document.documentElement.scrollHeight - window.innerHeight, - panelOverflow: panel ? panel.scrollHeight - panel.clientHeight : 0, - panelOverflowY: panel ? getComputedStyle(panel).overflowY : 'missing', + documentOverflowX: + document.documentElement.scrollWidth - window.innerWidth, + panelOverflowY: panel ? panel.scrollHeight - panel.clientHeight : 0, + panelOverflowX: panel ? panel.scrollWidth - panel.clientWidth : 0, + panelOverflowStyle: panel + ? getComputedStyle(panel).overflowY + : 'missing', }; }); check( '移动端游玩页不可滚动(面板与整页都不溢出)', - playScroll.documentOverflow <= 1 && - playScroll.panelOverflow <= 1 && - playScroll.panelOverflowY === 'hidden', + playScroll.documentOverflowY <= 1 && + playScroll.documentOverflowX <= 1 && + playScroll.panelOverflowY <= 1 && + playScroll.panelOverflowX <= 1 && + playScroll.panelOverflowStyle === 'hidden', JSON.stringify(playScroll), ); await mobile.close(); diff --git a/src/index.css b/src/index.css index cb2a68469..b348155d1 100644 --- a/src/index.css +++ b/src/index.css @@ -1180,8 +1180,14 @@ html[data-mobile-keyboard-open='true'] .platform-mobile-bottom-dock { */ } -/* 游玩页是固定画布:面板不滚动,播放器撑满剩余高度,移动端也不会整页可滚。 */ -.platform-tab-panel--game-play { +/* + * 游玩页是固定画布:面板不滚动,播放器撑满剩余高度,移动端也不会整页可滚。 + * 必须带上 workbench 祖先一起写:`.platform-desktop-shell--workbench .platform-tab-panel` + * 的 `overflow: auto` 是 (0,2,0),只写一个类会被它压掉(实测 computed overflow-y 仍是 auto)。 + */ +.platform-tab-panel--game-play, +.platform-desktop-shell--workbench + .platform-tab-panel.platform-tab-panel--game-play { overflow: hidden; }