You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

303 lines
8.1 KiB

import * as React from 'react';
import classNames from 'classnames';
import omit from 'omit.js';
import ResizeObserver from 'rc-resize-observer';
import { ConfigContext, ConfigConsumerProps } from '../config-provider';
import { throttleByAnimationFrameDecorator } from '../_util/throttleByAnimationFrame';
import {
addObserveTarget,
removeObserveTarget,
getTargetRect,
getFixedTop,
getFixedBottom,
} from './utils';
function getDefaultTarget() {
return typeof window !== 'undefined' ? window : null;
}
// Affix
export interface AffixProps {
/**
*
*/
offsetTop?: number;
/** 距离窗口底部达到指定偏移量后触发 */
offsetBottom?: number;
style?: React.CSSProperties;
/** 固定状态改变时触发的回调函数 */
onChange?: (affixed?: boolean) => void;
/** 设置 Affix 需要监听其滚动事件的元素,值为一个返回对应 DOM 元素的函数 */
target?: () => Window | HTMLElement | null;
prefixCls?: string;
className?: string;
children: React.ReactNode;
6 years ago
}
enum AffixStatus {
None,
Prepare,
}
export interface AffixState {
6 years ago
affixStyle?: React.CSSProperties;
placeholderStyle?: React.CSSProperties;
status: AffixStatus;
lastAffix: boolean;
prevTarget: Window | HTMLElement | null;
}
6 years ago
class Affix extends React.Component<AffixProps, AffixState> {
static contextType = ConfigContext;
6 years ago
state: AffixState = {
6 years ago
status: AffixStatus.None,
6 years ago
lastAffix: false,
prevTarget: null,
6 years ago
};
6 years ago
placeholderNode: HTMLDivElement;
6 years ago
fixedNode: HTMLDivElement;
6 years ago
private timeout: number;
context: ConfigConsumerProps;
private getTargetFunc() {
const { getTargetContainer } = this.context;
const { target } = this.props;
if (target !== undefined) {
return target;
}
return getTargetContainer || getDefaultTarget;
}
6 years ago
// Event handler
componentDidMount() {
const targetFunc = this.getTargetFunc();
if (targetFunc) {
6 years ago
// [Legacy] Wait for parent component ref has its value.
// We should use target as directly element instead of function which makes element check hard.
6 years ago
this.timeout = setTimeout(() => {
addObserveTarget(targetFunc(), this);
6 years ago
// Mock Event object.
this.updatePosition();
6 years ago
});
}
}
6 years ago
componentDidUpdate(prevProps: AffixProps) {
const { prevTarget } = this.state;
const targetFunc = this.getTargetFunc();