@uiw/react-affix
Version:
Affix component
142 lines • 4.18 kB
JavaScript
import _objectWithoutPropertiesLoose from "@babel/runtime/helpers/objectWithoutPropertiesLoose";
import _extends from "@babel/runtime/helpers/extends";
var _excluded = ["prefixCls", "className", "children", "offsetTop", "offsetBottom", "target", "onChange"];
import React from 'react';
import { noop } from '@uiw/utils';
import { getDefaultTarget, getOffset } from './utils';
import { jsx as _jsx } from "react/jsx-runtime";
export default class Affix extends React.Component {
constructor(props) {
super(props);
this.state = {
placeholderStyle: undefined,
affixStyle: undefined
};
this.box = void 0;
this.target = void 0;
this.events = ['resize', 'scroll', 'touchstart', 'touchmove', 'touchend', 'pageshow', 'load'];
this.eventHandlers = {};
this.timeout = void 0;
this.getInstance = node => {
if (node) {
this.box = node;
}
};
this.updatePosition = this.updatePosition.bind(this);
}
componentDidMount() {
var target = this.props.target || getDefaultTarget;
// Wait for parent component ref has its value
this.timeout = window.setTimeout(() => {
this.target = target();
this.setTargetEventListeners();
});
}
componentWillUnmount() {
this.clearEventListeners();
clearTimeout(this.timeout);
}
updatePosition() {
var {
offsetTop
} = this.props;
var {
offsetBottom
} = this.props;
if (!this.box || !this.box.offsetParent) {
return;
}
var elemSize = {
width: this.box.clientWidth,
height: this.box.clientHeight
};
var offsetMode = {
top: true,
bottom: false
};
if (typeof offsetTop !== 'number' && typeof offsetBottom !== 'number') {
offsetMode.top = true;
offsetTop = 0;
}
if (typeof offsetBottom === 'number') {
offsetMode.top = false;
offsetMode.bottom = true;
}
var elemOffset = getOffset(this.box, this.target);
var box = this.box.getBoundingClientRect();
var bottom = document.documentElement.clientHeight - box.y - elemOffset.height;
if (offsetMode.top && box.y < 0) {
this.setPlaceholderStyle(_extends({}, elemSize));
this.setAffixStyle({
position: 'fixed',
top: offsetTop || 0,
left: elemOffset.left,
width: elemOffset.width
});
} else if (offsetMode.bottom && bottom < 0) {
this.setPlaceholderStyle(_extends({}, elemSize));
this.setAffixStyle({
position: 'fixed',
bottom: offsetBottom || 0,
left: elemOffset.left,
width: elemOffset.width
});
} else {
this.setPlaceholderStyle();
this.setAffixStyle();
}
}
setAffixStyle(affixStyle) {
var {
onChange
} = this.props;
var affixed = !!this.state.affixStyle;
this.setState({
affixStyle
}, () => {
onChange && onChange(affixed);
});
}
setPlaceholderStyle(placeholderStyle) {
this.setState({
placeholderStyle
});
}
// 设置监听事件
setTargetEventListeners() {
this.clearEventListeners();
this.events.forEach(eventName => {
this.eventHandlers[eventName] = this.updatePosition;
this.target && this.target.addEventListener(eventName, this.updatePosition, false);
});
}
clearEventListeners() {
this.events.forEach(eventName => {
var handler = this.eventHandlers[eventName];
this.target && this.target.removeEventListener(eventName, handler, false);
});
}
render() {
var _this$props = this.props,
{
prefixCls,
className,
children
} = _this$props,
resetProps = _objectWithoutPropertiesLoose(_this$props, _excluded);
var cls = [className, prefixCls].filter(Boolean).join(' ').trim();
return /*#__PURE__*/_jsx("div", _extends({}, resetProps, {
ref: this.getInstance,
style: _extends({}, this.state.placeholderStyle, this.props.style),
children: /*#__PURE__*/_jsx("div", {
className: cls,
style: this.state.affixStyle,
children: children
})
}));
}
}
Affix.defaultProps = {
prefixCls: 'w-affix',
onChange: noop
};