From 7adcbcf9814dd5da425853ff5dcb88993388691e Mon Sep 17 00:00:00 2001 From: Johnny Zhang Date: Thu, 3 Sep 2026 14:01:34 +0800 Subject: [PATCH] =?UTF-8?q?fix(header):=20=E8=B4=A6=E5=8F=B7=E8=8F=9C?= =?UTF-8?q?=E5=8D=95=E4=B8=8D=E5=86=8D=E5=9C=A8=E6=8C=87=E9=92=88=E7=A7=BB?= =?UTF-8?q?=E5=87=BA=E5=A4=B4=E5=83=8F=E6=97=B6=E5=85=B3=E9=97=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 鼠标从头像走到菜单必然经过两者之间的空隙,pointerleave 让菜单 在指针到达之前就关闭,账号中心、修改密码、退出登录三项鼠标点不到。 --- frontend/src/app/layout/app-header.test.tsx | 18 ++++++++++++++---- frontend/src/app/layout/app-header.tsx | 7 ++++++- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/frontend/src/app/layout/app-header.test.tsx b/frontend/src/app/layout/app-header.test.tsx index 06ce90b6..c023da86 100644 --- a/frontend/src/app/layout/app-header.test.tsx +++ b/frontend/src/app/layout/app-header.test.tsx @@ -486,13 +486,12 @@ describe('AppHeader', () => { ) }) - it('账号菜单在点击外部、按 Escape 或指针移出账号区域时关闭', async () => { + it('账号菜单在点击外部或按 Escape 时关闭', async () => { window.localStorage.setItem('windup.auth.refresh-token', 'stored-refresh-token') renderHeader('/workspace') const trigger = await screen.findByRole('button', { name: '打开账号菜单' }) const menu = screen.getByTestId('account-menu') - const accountRegion = screen.getByLabelText('账号') fireEvent.click(trigger) fireEvent.pointerDown(document.body) @@ -502,11 +501,22 @@ describe('AppHeader', () => { fireEvent.click(trigger) fireEvent.keyDown(document, { key: 'Escape' }) expect(menu.getAttribute('data-state')).toBe('closing') - fireEvent.animationEnd(menu) + }) + + it('指针移出头像所在区域时账号菜单保持打开,否则鼠标够不到菜单项', async () => { + window.localStorage.setItem('windup.auth.refresh-token', 'stored-refresh-token') + renderHeader('/workspace') + + const trigger = await screen.findByRole('button', { name: '打开账号菜单' }) + const menu = screen.getByTestId('account-menu') + const accountRegion = screen.getByLabelText('账号') fireEvent.click(trigger) + expect(menu.getAttribute('data-state')).toBe('open') + fireEvent.pointerLeave(accountRegion) - expect(menu.getAttribute('data-state')).toBe('closing') + expect(menu.getAttribute('data-state')).toBe('open') + expect(screen.getByRole('link', { name: '打开账号中心' })).toBeTruthy() }) it('让登录用户从 Header 的账号信息进入账号中心', async () => { diff --git a/frontend/src/app/layout/app-header.tsx b/frontend/src/app/layout/app-header.tsx index f3af007d..dfe556d2 100644 --- a/frontend/src/app/layout/app-header.tsx +++ b/frontend/src/app/layout/app-header.tsx @@ -348,10 +348,15 @@ export function AppHeader({ })} + {/* + 不挂 pointerleave 关闭:菜单是点击打开的,而它右对齐、比头像宽, + 与头像之间还隔着 0.5rem。鼠标从头像走向菜单的任何一条路径都会先离开本区域, + 于是菜单在指针到达之前就关掉,鼠标用户永远点不到里面的项。 + 关闭交给区域外 pointerdown、Escape 和焦点移出。 + */}
{ if (!event.currentTarget.contains(event.relatedTarget as Node | null)) { accountMenu.close()