From 8dc7201eb4787e42a5a9fc14b9f8bf79c2487e27 Mon Sep 17 00:00:00 2001 From: HIsheR Date: Mon, 26 Oct 2026 23:19:02 +0800 Subject: [PATCH] =?UTF-8?q?iter(g289):=20=E6=B0=94=E6=B3=A1=E8=B7=9F?= =?UTF-8?q?=E9=9A=8F=E6=BB=9A=E5=8A=A8=E9=87=8D=E7=AE=97=E7=BF=BB=E8=BD=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .ua/index.json | 5 +++-- llms-full.txt | 3 ++- packages/skin/ui/src/tooltip.ts | 31 ++++++++++++++++++++++++++++++- packages/skin/ui/ua.manifest.json | 3 ++- 4 files changed, 37 insertions(+), 5 deletions(-) diff --git a/.ua/index.json b/.ua/index.json index 275fff3..eee4d91 100644 --- a/.ua/index.json +++ b/.ua/index.json @@ -1,6 +1,6 @@ { "$schema": "ui-arch-registry-index/0.1", - "generatedAt": "2026-10-26T15:18:04.340Z", + "generatedAt": "2026-10-26T15:18:47.384Z", "repoRoot": ".", "packages": [ { @@ -1323,7 +1323,8 @@ "鼠标悬停或键盘聚焦后延迟 delay 毫秒出场,移出 / 失焦 / Esc 收起;空间不足时自动翻到另一侧", "触摸屏没有 hover:手指按下即出场,抬手后停留 1.2 秒再收起,免得手指正挡着就消失", "气泡设了 pointer-events: none,不会挡住下面的点击;aria-describedby 已关联,读屏能念出提示文案", - "方位支持上下左右四向:贴边或工具栏竖排时用 left / right,出场时按该方向剩余空间自动翻到对侧" + "方位支持上下左右四向:贴边或工具栏竖排时用 left / right,出场时按该方向剩余空间自动翻到对侧", + "出场期间滚动页面或任意滚动容器,气泡会按视口重算上下翻转(rAF 节流);收起后监听立即摘掉,不在关闭态空转" ] }, { diff --git a/llms-full.txt b/llms-full.txt index 2fdaa86..263555a 100644 --- a/llms-full.txt +++ b/llms-full.txt @@ -1,6 +1,6 @@ # @ui-arch 组件库 Agent 文档(无图形版) -> 自动生成于 2026-10-26T15:18:04.340Z,数据源:各包 ua.manifest.json,勿手改。人类版文档站:apps/docs/index.html。 +> 自动生成于 2026-10-26T15:18:47.384Z,数据源:各包 ua.manifest.json,勿手改。人类版文档站:apps/docs/index.html。 > 组件 = 普通函数,传 props 返回 DOM;状态用 signal 双向绑定:读 signal() 写 signal(v)。 ## 快速上手 @@ -630,6 +630,7 @@ tooltip({ content: '保存后立即生效' }, button({ label: '保存', onClick: 3. 触摸屏没有 hover:手指按下即出场,抬手后停留 1.2 秒再收起,免得手指正挡着就消失 4. 气泡设了 pointer-events: none,不会挡住下面的点击;aria-describedby 已关联,读屏能念出提示文案 5. 方位支持上下左右四向:贴边或工具栏竖排时用 left / right,出场时按该方向剩余空间自动翻到对侧 +6. 出场期间滚动页面或任意滚动容器,气泡会按视口重算上下翻转(rAF 节流);收起后监听立即摘掉,不在关闭态空转 现场演示:apps/docs/demo.html#sec-tooltip diff --git a/packages/skin/ui/src/tooltip.ts b/packages/skin/ui/src/tooltip.ts index 5a3617f..60fca66 100644 --- a/packages/skin/ui/src/tooltip.ts +++ b/packages/skin/ui/src/tooltip.ts @@ -57,6 +57,31 @@ export function tooltip(props: TooltipProps, trigger: HTMLElement): HTMLElement ); const root = h('span', { class: 'ua-tip-wrap' }, trigger, bubble); + // —— 出场期间的位置跟随:气泡本身是 wrap 内的绝对定位(滚动时跟着走),但翻转判定看的是视口, + // 页面或任意滚动容器一滚就可能变成「朝上放不下」——所以出场时挂监听,收起时摘掉(不在关闭态空转) —— + let bound = false; // 监听是否已挂:重复出场不重复绑定 + let raf = 0; // rAF 节流句柄:滚动事件高频,一帧最多重算一次 + const reflow = (): void => place(flipSide(trigger, bubble, props.placement ?? 'top')); + const onShift = (): void => { + if (raf) return; + raf = requestAnimationFrame(() => { + raf = 0; + reflow(); + }); + }; + const bind = (): void => { + if (bound) return; + bound = true; + window.addEventListener('scroll', onShift, true); // 捕获阶段:滚动容器的 scroll 不冒泡,只有捕获能收到 + window.addEventListener('resize', onShift); + }; + const unbind = (): void => { + if (!bound) return; + bound = false; + window.removeEventListener('scroll', onShift, true); + window.removeEventListener('resize', onShift); + }; + root.addEventListener('pointerenter', (e: PointerEvent) => { if (e.pointerType !== 'touch') show(); }); // 鼠标进入(触摸交给下面的点按) root.addEventListener('pointerleave', (e: PointerEvent) => { if (e.pointerType !== 'touch') hide(); }); // 鼠标离开 root.addEventListener('focusin', show); // 键盘聚焦(focusin 会冒泡) @@ -64,7 +89,11 @@ export function tooltip(props: TooltipProps, trigger: HTMLElement): HTMLElement // —— 触摸屏:没有 hover,改点按。按下即出(不等 150ms),抬手留 1.2s 再收,否则手指正挡着气泡就没了 —— root.addEventListener('pointerdown', (e: PointerEvent) => { if (e.pointerType === 'touch') show(); }); root.addEventListener('pointerup', (e: PointerEvent) => { if (e.pointerType === 'touch') hideLater(); }); - effect(() => { if (open()) place(flipSide(trigger, bubble, props.placement ?? 'top')); }); // 每次出场重算方位:空间不足自动翻转 + effect(() => { + if (!open()) return unbind(); // 收起即摘监听:气泡不在,重算方位没有意义 + place(flipSide(trigger, bubble, props.placement ?? 'top')); // 出场先算一次:空间不足自动翻转 + bind(); // 出场期间跟着滚动 / 缩放重算:wrap 定位不会飘,但「视口里还放得下吗」会过期 + }); root.addEventListener('keydown', (e: KeyboardEvent) => { if (e.key === 'Escape') { e.stopPropagation(); hide(); } // Esc 立即收起且不影响外层弹层 }); diff --git a/packages/skin/ui/ua.manifest.json b/packages/skin/ui/ua.manifest.json index e5e7d89..a632b3c 100644 --- a/packages/skin/ui/ua.manifest.json +++ b/packages/skin/ui/ua.manifest.json @@ -1194,7 +1194,8 @@ "鼠标悬停或键盘聚焦后延迟 delay 毫秒出场,移出 / 失焦 / Esc 收起;空间不足时自动翻到另一侧", "触摸屏没有 hover:手指按下即出场,抬手后停留 1.2 秒再收起,免得手指正挡着就消失", "气泡设了 pointer-events: none,不会挡住下面的点击;aria-describedby 已关联,读屏能念出提示文案", - "方位支持上下左右四向:贴边或工具栏竖排时用 left / right,出场时按该方向剩余空间自动翻到对侧" + "方位支持上下左右四向:贴边或工具栏竖排时用 left / right,出场时按该方向剩余空间自动翻到对侧", + "出场期间滚动页面或任意滚动容器,气泡会按视口重算上下翻转(rAF 节流);收起后监听立即摘掉,不在关闭态空转" ] }, {