InfoLens / client /src /ts /ui /cssPseudoFullscreen.ts
dqy08's picture
initial beta release
494c9e4
/**
* WORKAROUND:CSS 伪全屏(fixed + 锁 body 滚动)
*
* 不参与 Fullscreen API。供「原生 `requestFullscreen` 不可用或拒绝」时降级使用;
* 业务层应始终先尝试标准 API,再把本模块当作兜底(见 `genAttributeDagFullscreenWorkaround.ts`)。
*
* 样式类名 {@link CSS_PSEUDO_FULLSCREEN_TARGET_CLASS} 须与页面 SCSS 一致。
*/
/** 须与 gen_attribute.scss 中 WORKAROUND 段落的选择器一致 */
export const CSS_PSEUDO_FULLSCREEN_TARGET_CLASS = 'css-pseudo-fullscreen-target';
const BODY_LOCK_CLASS = 'css-pseudo-fullscreen-body-lock';
/** 伪全屏进/出时派发(`fullscreenchange` 不会为此触发) */
export const CSS_PSEUDO_FULLSCREEN_CHANGE_EVENT = 'css-pseudo-fullscreen-change';
let activeTarget: HTMLElement | null = null;
let escapeListener: ((e: KeyboardEvent) => void) | null = null;
function teardownEscape(): void {
if (escapeListener) {
document.removeEventListener('keydown', escapeListener);
escapeListener = null;
}
}
function notifyChange(): void {
document.dispatchEvent(new CustomEvent(CSS_PSEUDO_FULLSCREEN_CHANGE_EVENT));
}
export function cssPseudoFullscreenIsActive(el?: HTMLElement): boolean {
if (!activeTarget) return false;
return el === undefined ? true : activeTarget === el;
}
export function cssPseudoFullscreenEnter(el: HTMLElement): void {
if (activeTarget === el) return;
if (activeTarget && activeTarget !== el) cssPseudoFullscreenExit();
activeTarget = el;
activeTarget.classList.add(CSS_PSEUDO_FULLSCREEN_TARGET_CLASS);
document.body.classList.add(BODY_LOCK_CLASS);
teardownEscape();
// 原生全屏时浏览器自己处理 Escape;伪全屏不走 Fullscreen API,须自行监听。
escapeListener = (e: KeyboardEvent): void => {
if (e.key === 'Escape') {
cssPseudoFullscreenExit();
}
};
document.addEventListener('keydown', escapeListener);
notifyChange();
}
export function cssPseudoFullscreenExit(el?: HTMLElement): void {
if (!activeTarget) return;
if (el !== undefined && activeTarget !== el) return;
activeTarget.classList.remove(CSS_PSEUDO_FULLSCREEN_TARGET_CLASS);
document.body.classList.remove(BODY_LOCK_CLASS);
activeTarget = null;
teardownEscape();
notifyChange();
}