feat(webui): 回复/转发动画真的会播了 + 写邮件改成「按钮长成整页」
用户两问:
① 「回复邮件那个按钮还是没有动画」——**我上一版的锅**:我只给回复框/转发面板挂了
`rise-in`,但那条规则写作 `html.view-switch .rise-in`,而 view-switch 窗口只由
视图/页签/窄屏/写信 四个状态触发。**回复/转发根本不触发它** ⇒ 类挂着、动画永远不播。
我当时的"验证"只覆盖了写信页(恰好命中四个触发之一),另外两处只验了类在不在。
② 「写邮件的按钮点击不应该是一个按钮扩大变成页面的动画吗?」——是,这才是对的形态。
改法:
- 拆两档作用域:`.rise-in` **挂载即播**(给"点了才出现"的面:写信页/回复框/转发面板),
`.pane-rise` 由 `html.view-switch` 窗口触发(给常驻面板:列表栏/日历)。
首屏不会有一堆东西同时淡入,因为前者只在用户动作时挂载。
- 新增 lib/composeOrigin.ts:在**捕获阶段**记录被点元素的矩形(React 的 onClick 在冒泡
阶段,晚一步就取不到),带 2s 时效(防止"点了别的按钮 → 稍后被程序化打开写信页"时
从旧按钮长出来);优先认 `data-compose-trigger`,退一步认最近的 button,
这样 4 个入口不必逐个改(漏一个的后果是静默无动画,与 ① 同一种失败)。
- ComposePage:有起点就 el.animate 从那个矩形长成整页(220ms,只动
transform/opacity/border-radius —— 合成器可做,不动宽高),没起点退回 rise-in。
两条动画都动 transform/opacity,所以渲染期就决定挂哪一条,不同时挂。
判据(narrow-layout +6):rise-in 必须不带 view-switch 前缀、常驻面板必须用 pane-rise
且 window 规则在、reduced-motion 覆盖两档、morph 只动合成器属性、有起点 morph /
无起点 rise-in。生产实测:点悬浮球后 document.getAnimations() 里 ComposePage 根节点上
有 running 的 220ms 动画,首帧 translate(-564px,396px) scale(0.0549)、opacity 0.3
(悬浮球 56px ⇒ scale≈0.055)。回复框/转发面板因该账号收件箱为空未点穿,但触发条件
已从我写错的"窗口触发"改成"挂载即播"。
This commit is contained in:
@ -269,6 +269,34 @@ check(
|
||||
/rise-in/.test(composeSrc) && (mailViewSrc.match(/rise-in/g) || []).length >= 2,
|
||||
'三处目标面没都穿上 rise-in(回复框与转发面板在 MailView 里,必须各有一处)'
|
||||
);
|
||||
|
||||
/*
|
||||
* 「按钮长成页面」(2026-09-15 用户:「写邮件的按钮点击不应该是一个按钮扩大变成页面的
|
||||
* 动画吗?」)。判据钉四件事,都是**接线**而不是数值:
|
||||
* ① 起点捕获存在,且在**捕获阶段**(React 的 onClick 在冒泡阶段,晚一步就取不到矩形);
|
||||
* ② 有 TTL —— 否则"点别的按钮 → 过一会儿程序化打开写信页"会从旧按钮长出来;
|
||||
* ③ morph 只动 transform/opacity/border-radius(合成器可做,不触发布局);
|
||||
* ④ 有起点时不挂 rise-in(两条动画都动 transform/opacity,同挂会打架),
|
||||
* 没起点时必须退回 rise-in(否则刷新后直接进写信页就彻底没动画)。
|
||||
*/
|
||||
const originSrc = code('src/lib/composeOrigin.ts');
|
||||
const composeSrc2 = code('src/components/ComposePage.tsx');
|
||||
check(
|
||||
'写信页起点矩形:捕获阶段取 + 有时效',
|
||||
/addEventListener\(\s*'click'/.test(originSrc) && /,\s*true\s*\)/.test(originSrc) && /TTL_MS/.test(originSrc),
|
||||
'起点捕获要么没在捕获阶段(拿不到矩形),要么没有时效(会从不相干的旧按钮长出来)'
|
||||
);
|
||||
check(
|
||||
'按钮→页面 morph 只动合成器属性',
|
||||
/el\.animate\(/.test(composeSrc2) && /transform:/.test(composeSrc2) && !/height:|width:\s*`/.test(composeSrc2),
|
||||
'morph 动了布局属性(宽高)—— 那会逐帧重排,正是"卡顿"的来源'
|
||||
);
|
||||
check(
|
||||
'有起点做 morph、没起点退回 rise-in',
|
||||
/fromRect \? '' : 'rise-in '/.test(composeSrc2) && /peekComposeOrigin/.test(composeSrc2),
|
||||
'两条动画会同时挂,或者丢了无起点时的兜底'
|
||||
);
|
||||
|
||||
check(
|
||||
'动画走合成器(view-switch 窗口内提层)',
|
||||
/html\.view-switch \.rise-in\s*\{[\s\S]*?will-change:\s*transform,\s*opacity/.test(css),
|
||||
@ -280,14 +308,29 @@ check(
|
||||
!/void\s+root\.offsetWidth/.test(appMotionSrc) && /requestAnimationFrame/.test(appMotionSrc),
|
||||
'触发动画还在读 offsetWidth(同步强制布局)—— 这笔记账正好落在动画第一帧上,就是卡顿的来源之一'
|
||||
);
|
||||
/*
|
||||
* ★ 2026-09-15 用户:「回复邮件那个按钮还是没有动画」。我上一版给回复框/转发面板挂了
|
||||
* `rise-in`,但那条规则写作 `html.view-switch .rise-in` —— 而 view-switch 窗口只由
|
||||
* 视图/页签/窄屏/写信 四个状态触发,**回复/转发不触发它** ⇒ 类挂了、动画永远不播。
|
||||
* 现在拆两档:`.rise-in` 挂载即播(点了才出现的面),`.pane-rise` 由窗口触发(常驻面板)。
|
||||
* 判据必须钉住"这两档各自的作用域",否则同样的接线错误会再犯一次。
|
||||
*/
|
||||
const bareRise = (css.match(/(^|\n)\.rise-in\s*\{[\s\S]*?\n\}/) || [''])[0];
|
||||
check(
|
||||
'主要视图也穿 rise-in(列表/日历)',
|
||||
/rise-in/.test(code('src/components/MailList.tsx')) && /rise-in/.test(code('src/components/CalendarView.tsx')),
|
||||
'切到列表/日历时没有入场动画 —— "绝大部分场景还是没有流畅的动画"就是这一条'
|
||||
'「点了才出现」的面必须挂载即播(.rise-in 不带 view-switch 前缀)',
|
||||
/animation:\s*rise-in/.test(bareRise),
|
||||
'回复框/转发面板的动画仍被绑在 view-switch 窗口上 —— 那两个动作根本不会触发窗口,等于没动画'
|
||||
);
|
||||
check(
|
||||
'常驻面板用窗口触发的 pane-rise(列表/日历)',
|
||||
/pane-rise/.test(code('src/components/MailList.tsx')) &&
|
||||
/pane-rise/.test(code('src/components/CalendarView.tsx')) &&
|
||||
/html\.view-switch \.pane-rise\s*\{/.test(css),
|
||||
'列表/日历没有入场动画,或者把"常驻面板"误挂到了挂载即播的档上(首屏会跟着闪)'
|
||||
);
|
||||
check(
|
||||
'rise-in 也受 prefers-reduced-motion 管',
|
||||
reducedBlocks.some(b => /view-switch \.rise-in/.test(b)),
|
||||
reducedBlocks.some(b => /view-switch \.rise-in/.test(b)) && reducedBlocks.some(b => /view-switch \.pane-rise/.test(b)),
|
||||
'reduced-motion 块里漏了 rise-in —— 关掉动画的人仍会被它位移'
|
||||
);
|
||||
check(
|
||||
|
||||
Reference in New Issue
Block a user