iter(g300): 修正 toast 悬停暂停从未生效

This commit is contained in:
HIsheR
2026-10-27 00:25:55 +08:00
parent a8ff91c0a8
commit c013998f88
7 changed files with 51 additions and 20 deletions
+16 -2
View File
@@ -4,6 +4,7 @@ import type { ToastProps } from './types.js';
let host: HTMLElement | null = null; // 全局右上角堆叠容器:首条消息出现时懒创建
let seq = 0; // 自增序号:为每条 toast 生成唯一 id,辅助无障碍定位
const MAX_STACK = 4; // 同屏最多条数:超出即挤掉最早一条,避免刷屏淹页面
const PAUSE_FLOOR = 400; // 恢复时的最短剩余毫秒:悬停前已近归零也不至于松手即消失
/*** 确保堆叠容器存在:fixed 挂在 body 末尾,后续消息依次向上堆叠 ***/
function ensureHost(): HTMLElement {
@@ -43,10 +44,23 @@ export function showToast(props: ToastProps): HTMLElement {
stack.appendChild(item);
requestAnimationFrame(() => item.classList.add('ua-open')); // 下一帧入场,保证过渡生效
const arm = (ms: number): void => { startedAt = Date.now(); timer = window.setTimeout(() => dismiss(item), ms); }; // 重新武装倒计时
/*** 暂停倒计时:扣掉本段已走时长,清空句柄(重复进入不会二次扣减) ***/
const pause = (): void => {
if (!timer) return; // 已暂停 / 常驻(duration 为 0)时无计时器可停
window.clearTimeout(timer);
timer = 0;
remain = Math.max(PAUSE_FLOOR, remain - (Date.now() - startedAt));
};
/*** 恢复倒计时:按剩余时长重新武装 ***/
const resume = (): void => { if (!timer && remain > 0) arm(remain); };
if (duration > 0) {
arm(duration);
item.addEventListener('pointerenter', () => { window.clearTimeout(timer); remain -= Date.now() - startedAt; }); // 悬停暂停:记下剩余时长
item.addEventListener('pointerleave', () => arm(remain)); // 移出后按剩余时长继续
item.addEventListener('pointerenter', pause); // 悬停停留阅读:倒计时暂停
item.addEventListener('pointerleave', resume); // 移出后按剩余时长继续
item.addEventListener('focusin', pause); // 键盘 Tab 进关闭 / 操作按钮时同样暂停
item.addEventListener('focusout', (e) => {
if (!item.contains(e.relatedTarget as Node | null)) resume(); // 焦点还在卡片内部(按钮间切换)时不恢复
});
}
return item;
}