108 lines
		
	
	
		
			3.0 KiB
		
	
	
	
		
			TypeScript
		
	
	
			
		
		
	
	
			108 lines
		
	
	
		
			3.0 KiB
		
	
	
	
		
			TypeScript
		
	
	
import addEventListener from '../vc-util/Dom/addEventListener';
 | 
						|
import supportsPassive from '../_util/supportsPassive';
 | 
						|
 | 
						|
export type BindElement = HTMLElement | Window | null | undefined;
 | 
						|
 | 
						|
export function getTargetRect(target: BindElement): DOMRect {
 | 
						|
  return target !== window
 | 
						|
    ? (target as HTMLElement).getBoundingClientRect()
 | 
						|
    : ({ top: 0, bottom: window.innerHeight } as DOMRect);
 | 
						|
}
 | 
						|
 | 
						|
export function getFixedTop(placeholderRect: DOMRect, targetRect: DOMRect, offsetTop: number) {
 | 
						|
  if (offsetTop !== undefined && targetRect.top > placeholderRect.top - offsetTop) {
 | 
						|
    return `${offsetTop + targetRect.top}px`;
 | 
						|
  }
 | 
						|
  return undefined;
 | 
						|
}
 | 
						|
 | 
						|
export function getFixedBottom(
 | 
						|
  placeholderRect: DOMRect,
 | 
						|
  targetRect: DOMRect,
 | 
						|
  offsetBottom: number,
 | 
						|
) {
 | 
						|
  if (offsetBottom !== undefined && targetRect.bottom < placeholderRect.bottom + offsetBottom) {
 | 
						|
    const targetBottomOffset = window.innerHeight - targetRect.bottom;
 | 
						|
    return `${offsetBottom + targetBottomOffset}px`;
 | 
						|
  }
 | 
						|
  return undefined;
 | 
						|
}
 | 
						|
 | 
						|
// ======================== Observer ========================
 | 
						|
const TRIGGER_EVENTS = [
 | 
						|
  'resize',
 | 
						|
  'scroll',
 | 
						|
  'touchstart',
 | 
						|
  'touchmove',
 | 
						|
  'touchend',
 | 
						|
  'pageshow',
 | 
						|
  'load',
 | 
						|
];
 | 
						|
 | 
						|
interface ObserverEntity {
 | 
						|
  target: HTMLElement | Window;
 | 
						|
  affixList: any[];
 | 
						|
  eventHandlers: { [eventName: string]: any };
 | 
						|
}
 | 
						|
 | 
						|
let observerEntities: ObserverEntity[] = [];
 | 
						|
 | 
						|
export function getObserverEntities() {
 | 
						|
  // Only used in test env. Can be removed if refactor.
 | 
						|
  return observerEntities;
 | 
						|
}
 | 
						|
 | 
						|
export function addObserveTarget<T>(target: HTMLElement | Window | null, affix: T): void {
 | 
						|
  if (!target) return;
 | 
						|
 | 
						|
  let entity = 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 => {
 | 
						|
      entity!.eventHandlers[eventName] = addEventListener(target, eventName, () => {
 | 
						|
        entity!.affixList.forEach(
 | 
						|
          targetAffix => {
 | 
						|
            const { lazyUpdatePosition } = (targetAffix as any).exposed;
 | 
						|
            lazyUpdatePosition();
 | 
						|
          },
 | 
						|
          (eventName === 'touchstart' || eventName === 'touchmove') && supportsPassive
 | 
						|
            ? ({ passive: true } as EventListenerOptions)
 | 
						|
            : false,
 | 
						|
        );
 | 
						|
      });
 | 
						|
    });
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
export function removeObserveTarget<T>(affix: T): void {
 | 
						|
  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();
 | 
						|
      }
 | 
						|
    });
 | 
						|
  }
 | 
						|
}
 |