iter(g80): 通知悬停与聚焦暂停自动关闭计时
This commit is contained in:
@@ -19,12 +19,15 @@ function dismiss(item: HTMLElement): void {
|
||||
window.setTimeout(() => item.isConnected && item.remove(), 320); // reduced-motion 下不触发 transition
|
||||
}
|
||||
|
||||
/*** 通知卡片:标题 + 描述 + 可选操作区,返回 { el, close } 句柄;duration 为 0 表示常驻 ***/
|
||||
/*** 通知卡片:标题 + 描述 + 可选操作区,返回 { el, close } 句柄;duration 为 0 表示常驻,非 0 时悬停 / 聚焦自动暂停计时 ***/
|
||||
export function notification(props: NotificationProps): { el: HTMLElement; close: () => void } {
|
||||
// —— 状态集中声明 ——
|
||||
const duration = props.duration ?? 0; // 缺省常驻:通知通常需要用户读完
|
||||
const closable = props.closable ?? true; // 缺省带关闭按钮
|
||||
let timer = 0; // 自动关闭计时器句柄
|
||||
let remain = duration; // 剩余毫秒:暂停时扣减,续计时接着走
|
||||
let startedAt = 0; // 本轮计时起点,用于折算暂停前已流逝的时间
|
||||
let paused = false; // 是否因悬停 / 聚焦而暂停
|
||||
const closeBtn = h('button', { type: 'button', class: 'ua-notice-close', 'aria-label': '关闭通知' }, '×') as HTMLButtonElement; // 关闭按钮,回调在下方绑定
|
||||
const el = h(
|
||||
'div',
|
||||
@@ -47,10 +50,21 @@ export function notification(props: NotificationProps): { el: HTMLElement; close
|
||||
};
|
||||
closeBtn.addEventListener('click', () => close());
|
||||
|
||||
/*** 起表:按剩余毫秒设定时器 ***/
|
||||
const arm = () => { if (remain <= 0) return; startedAt = Date.now(); timer = window.setTimeout(() => dismiss(el), remain); };
|
||||
/*** 暂停计时:扣掉已流逝部分,剩余时间留给续计 ***/
|
||||
const pause = () => { if (paused || remain <= 0) return; paused = true; window.clearTimeout(timer); remain -= Date.now() - startedAt; };
|
||||
/*** 续计:离开后按剩余毫秒重新起表 ***/
|
||||
const resume = () => { if (!paused) return; paused = false; arm(); };
|
||||
el.addEventListener('pointerenter', pause); // 悬停阅读时不倒计时
|
||||
el.addEventListener('pointerleave', resume);
|
||||
el.addEventListener('focusin', pause); // 键盘聚焦到关闭/操作按钮同样暂停
|
||||
el.addEventListener('focusout', resume);
|
||||
|
||||
const stack = ensureHost();
|
||||
if (stack.childElementCount >= MAX_STACK) stack.firstElementChild?.remove(); // 超出上限挤掉最早一条
|
||||
stack.appendChild(el);
|
||||
requestAnimationFrame(() => el.classList.add('ua-open')); // 下一帧入场,保证过渡生效
|
||||
if (duration > 0) timer = window.setTimeout(() => dismiss(el), duration); // 常驻(0)不设定时器
|
||||
if (duration > 0) arm(); // 常驻(0)不设定时器
|
||||
return { el, close };
|
||||
}
|
||||
|
||||
@@ -2034,7 +2034,7 @@
|
||||
{
|
||||
"n": "duration",
|
||||
"t": "number",
|
||||
"d": "自动关闭毫秒;缺省 0 = 常驻不自动关"
|
||||
"d": "自动关闭毫秒;缺省 0 = 常驻不自动关,非 0 时悬停 / 聚焦暂停计时"
|
||||
},
|
||||
{
|
||||
"n": "closable",
|
||||
|
||||
Reference in New Issue
Block a user