Files
wehub-resource-sync 2114b14ee0
Sync main into demo / sync (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:35:26 +08:00

106 lines
2.9 KiB
TypeScript

/**
* 滚动状态观测模块
*
* 提供 window.__getScrollMeta__() 函数,供 Agent 按需读取当前页面的滚动容器状态。
*
* 使用方式:
* 1. 在滚动容器上添加 data-scroll-container="name" 和 data-scroll-direction="vertical|horizontal"
* 2. Agent 调用 window.__getScrollMeta__() 自动发现并读取所有滚动容器状态
*
* 示例:
* <div data-scroll-container="main" data-scroll-direction="vertical" className="overflow-auto">
*/
export interface ScrollMeta {
/** 当前滚动位置 (scrollTop 或 scrollLeft) */
position: number;
/** 最大可滚动距离 */
max: number;
/** 可视区域大小 */
viewport: number;
/** 内容总高度/宽度 */
total: number;
}
export type ScrollMetaMap = Record<string, ScrollMeta>;
/**
* 检查元素是否可见
*/
function isElementVisible(el: HTMLElement): boolean {
// visibility: hidden 是继承属性;app 容器设为 hidden 后,其后代 computedStyle.visibility 也会是 hidden
const computedStyle = getComputedStyle(el);
if (computedStyle.display === 'none' || computedStyle.visibility === 'hidden') {
return false;
}
// offsetParent 为 null 表示元素或其祖先可能是 display: none
// 但 position: fixed 的元素 offsetParent 也为 null,需要额外检查
if (el.offsetParent === null) {
let parent = el.parentElement;
while (parent) {
if (getComputedStyle(parent).display === 'none') return false;
parent = parent.parentElement;
}
}
return true;
}
/**
* 获取当前页面的滚动状态
* 自动发现所有带 data-scroll-container 属性的可见元素
*/
export function getScrollMeta(): ScrollMetaMap {
const meta: ScrollMetaMap = {};
try {
const containers = document.querySelectorAll('[data-scroll-container]');
containers.forEach((el) => {
if (!(el instanceof HTMLElement)) return;
// 跳过不可见的元素
if (!isElementVisible(el)) return;
const name = el.getAttribute('data-scroll-container');
if (!name) return;
const direction = el.getAttribute('data-scroll-direction') || 'vertical';
if (direction === 'vertical') {
meta[name] = {
position: el.scrollTop,
max: el.scrollHeight - el.clientHeight,
viewport: el.clientHeight,
total: el.scrollHeight,
};
} else {
meta[name] = {
position: el.scrollLeft,
max: el.scrollWidth - el.clientWidth,
viewport: el.clientWidth,
total: el.scrollWidth,
};
}
});
} catch (e) {
console.error('[scrollMeta] Error getting scroll meta:', e);
}
return meta;
}
/**
* 初始化滚动状态观测
*
* 调用后会在 window 上暴露:
* - __getScrollMeta__() - 读取当前页面的滚动状态(自动发现)
*/
export function initScrollMeta(): void {
if (typeof window !== 'undefined') {
window.__getScrollMeta__ = getScrollMeta;
}
}