UNPKG

@uiw/react-affix

Version:
142 lines 4.18 kB
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 };