2019-03-03 10:04:21 +08:00
|
|
|
import addEventListener from 'rc-util/lib/Dom/addEventListener';
|
|
|
|
|
2019-04-24 19:53:53 +08:00
|
|
|
export type BindElement = HTMLElement | Window | null | undefined;
|
|
|
|
|
2021-10-25 19:43:17 +08:00
|
|
|
export function getTargetRect(target: BindElement): DOMRect {
|
2019-04-24 19:53:53 +08:00
|
|
|
return target !== window
|
|
|
|
? (target as HTMLElement).getBoundingClientRect()
|
2021-10-25 19:43:17 +08:00
|
|
|
: ({ top: 0, bottom: window.innerHeight } as DOMRect);
|
2019-04-24 19:53:53 +08:00
|
|
|
}
|
|
|
|
|
2021-10-25 19:43:17 +08:00
|
|
|
export function getFixedTop(placeholderReact: DOMRect, targetRect: DOMRect, offsetTop?: number) {
|
2019-04-24 19:53:53 +08:00
|
|
|
if (offsetTop !== undefined && targetRect.top > placeholderReact.top - offsetTop) {
|
|
|
|
return offsetTop + targetRect.top;
|
|
|
|
}
|
|
|
|
return undefined;
|
|
|
|
}
|
|
|
|
|
2019-05-07 14:57:32 +08:00
|
|
|
export function getFixedBottom(
|
2021-10-25 19:43:17 +08:00
|
|
|
placeholderReact: DOMRect,
|
|
|
|
targetRect: DOMRect,
|
|
|
|
offsetBottom?: number,
|
2019-05-07 14:57:32 +08:00
|
|
|
) {
|
|
|
|
if (offsetBottom !== undefined && targetRect.bottom < placeholderReact.bottom + offsetBottom) {
|
2019-04-24 19:53:53 +08:00
|
|
|
const targetBottomOffset = window.innerHeight - targetRect.bottom;
|
|
|
|
return offsetBottom + targetBottomOffset;
|
|
|
|
}
|
|
|
|
return undefined;
|
|
|
|
}
|
|
|
|
|
2019-03-03 10:04:21 +08:00
|
|
|
// ======================== Observer ========================
|
|
|
|
const TRIGGER_EVENTS = [
|
|
|
|
'resize',
|
|
|
|
'scroll',
|
|
|
|
'touchstart',
|
|
|
|
'touchmove',
|
|
|
|
'touchend',
|
|
|
|
'pageshow',
|
|
|
|
'load',
|
|
|
|
];
|
|
|
|
|
|
|
|
interface ObserverEntity {
|
|
|
|
target: HTMLElement | Window;
|
2022-03-02 17:05:59 +08:00
|
|
|
affixList: any[];
|
2019-03-03 10:04:21 +08:00
|
|
|
eventHandlers: { [eventName: string]: any };
|
|
|
|
}
|
|
|
|
|
|
|
|
let observerEntities: ObserverEntity[] = [];
|
|
|
|
|
2019-04-18 01:33:05 +08:00
|
|
|
export function getObserverEntities() {
|
|
|
|
// Only used in test env. Can be removed if refactor.
|
|
|
|
return observerEntities;
|
|
|
|
}
|
|
|
|
|
2022-03-02 17:05:59 +08:00
|
|
|
export function addObserveTarget<T>(target: HTMLElement | Window | null, affix: T): void {
|
2019-03-03 10:04:21 +08:00
|
|
|
if (!target) return;
|
|
|
|
|
|
|
|
let entity: ObserverEntity | undefined = observerEntities.find(item => item.target === target);
|
|
|
|
|
|
|
|
if (entity) {
|
|
|
|
entity.affixList.push(affix);
|
|
|
|
} else {
|
|
|
|
entity = {
|
|
|
|
target,
|
|
|
|
affixList: [affix],
|
|
|
|
eventHandlers: {},
|
|
|
|
};
|
|
|
|
observerEntities.push(entity);
|
|
|
|
|
|
|
|
// Add listener
|
|
|
|
TRIGGER_EVENTS.forEach(eventName => {
|
2019-08-05 18:38:10 +08:00
|
|
|
entity!.eventHandlers[eventName] = addEventListener(target, eventName, () => {
|
|
|
|
entity!.affixList.forEach(targetAffix => {
|
|
|
|
targetAffix.lazyUpdatePosition();
|
2019-03-03 10:04:21 +08:00
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-02 17:05:59 +08:00
|
|
|
export function removeObserveTarget<T>(affix: T): void {
|
2019-03-03 10:04:21 +08:00
|
|
|
const observerEntity = observerEntities.find(oriObserverEntity => {
|
|
|
|
const hasAffix = oriObserverEntity.affixList.some(item => item === affix);
|
|
|
|
if (hasAffix) {
|
|
|
|
oriObserverEntity.affixList = oriObserverEntity.affixList.filter(item => item !== affix);
|
|
|
|
}
|
|
|
|
return hasAffix;
|
|
|
|
});
|
|
|
|
|
|
|
|
if (observerEntity && observerEntity.affixList.length === 0) {
|
|
|
|
observerEntities = observerEntities.filter(item => item !== observerEntity);
|
|
|
|
|
|
|
|
// Remove listener
|
|
|
|
TRIGGER_EVENTS.forEach(eventName => {
|
|
|
|
const handler = observerEntity.eventHandlers[eventName];
|
|
|
|
if (handler && handler.remove) {
|
|
|
|
handler.remove();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|