From 77717e439de3f979773bd4c626374090868084e2 Mon Sep 17 00:00:00 2001 From: yuetsh <517252939@qq.com> Date: Thu, 27 Aug 2026 11:18:12 -0600 Subject: [PATCH] =?UTF-8?q?fix(=E4=B8=BB=E9=A2=98=E5=88=87=E6=8D=A2):=20?= =?UTF-8?q?=E5=9C=86=E7=8E=AF=E4=BB=8E=E8=A7=86=E5=8F=A3=E6=AD=A3=E4=B8=AD?= =?UTF-8?q?=E6=89=A9=E6=95=A3=EF=BC=8C=E8=B7=9F=E7=82=B9=E5=87=BB=E7=9A=84?= =?UTF-8?q?=E5=9C=B0=E6=96=B9=E5=AF=B9=E4=B8=8D=E4=B8=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 深浅色切换的圆环扩散原本把圆心写死在 window.innerWidth / 2,不管点哪儿都从屏幕 正中冒出来。改成取指针落点。 半径也跟着修了。原来是 hypot(x, y),只量到左上角——圆心居中时恰好是对的,一挪到 按钮(在右上角)就不够长了,右下角会留一大块旧配色等圆环扩过去,看着像没刷新。 现在取到最远那个角的距离。 键盘触发(Enter / 空格)时 clientX/clientY 是 0,照用会让圆环从屏幕左上角冒出来, 这种情况退回按钮自身中心,用 event.detail === 0 判断。 startViewTransition 的降级判断原样保留,机房那批 Chrome 低于 94 仍然是直接切。 实测(钩住 documentElement.animate 看真实关键帧,视口 1280x633、按钮中心 1255,29): 点正中得 circle at 1255px 29px / r=1392.78,点按钮左上角 (1246,22) 得 at 1246px 22px, 说明跟的是指针不是按钮;键盘 Enter 得 at 1255px 29px,没跑到 (0,0)。三次主题都正确 翻转,无报错。 Co-Authored-By: Claude Opus 5 --- apps/web/src/shared/components/Header.vue | 24 +++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/apps/web/src/shared/components/Header.vue b/apps/web/src/shared/components/Header.vue index cefa154..67eaf6f 100644 --- a/apps/web/src/shared/components/Header.vue +++ b/apps/web/src/shared/components/Header.vue @@ -22,14 +22,30 @@ const { learnStep } = useLearnProgress() const isDark = useDark() -function toggleDark() { - const x = window.innerWidth / 2 - const y = window.innerHeight / 2 - const radius = Math.hypot(x, y) +/** + * 圆环从哪儿开始扩散。正常点击就用指针落点;键盘触发(Enter / 空格)时浏览器给的 + * clientX/clientY 是 0,照用会让圆环从屏幕左上角冒出来——那种情况退回按钮自己的中心。 + * `event.detail` 是点击次数,键盘触发时为 0,用它区分最省事。 + */ +function revealOrigin(event: MouseEvent) { + if (event.detail > 0) return { x: event.clientX, y: event.clientY } + const rect = (event.currentTarget as HTMLElement).getBoundingClientRect() + return { x: rect.left + rect.width / 2, y: rect.top + rect.height / 2 } +} + +function toggleDark(event: MouseEvent) { if (!document.startViewTransition) { + // 机房那批 Chrome 低于 94,没有 View Transitions,直接切、不做动画。 isDark.value = !isDark.value return } + const { x, y } = revealOrigin(event) + // 半径要取到**最远**那个角的距离。用 hypot(x, y) 只覆盖到左上角, + // 点在偏左上时右下角会有一块旧画面等圆环扩过去,看着像是没刷新。 + const radius = Math.hypot( + Math.max(x, window.innerWidth - x), + Math.max(y, window.innerHeight - y), + ) document .startViewTransition(() => { isDark.value = !isDark.value