UNPKG

@cainiaofe/cn-ui-m

Version:
89 lines (88 loc) 4.53 kB
import React, { useCallback, useEffect, useLayoutEffect, useRef, useState, } from 'react'; import { getScrollContainer } from "../../utils/dom"; import { withNativeProps } from '@cainiaofe/cn-ui-common'; /** * @category 组件 * 固钉 */ export var CnAffix = function (prop) { var children = prop.children, container = prop.container, disabled = prop.disabled, offsetTop = prop.offsetTop, zIndex = prop.zIndex, onAffix = prop.onAffix; var boxRef = useRef(null); var contentRef = useRef(null); var boxElement = boxRef === null || boxRef === void 0 ? void 0 : boxRef.current; var contentElement = contentRef === null || contentRef === void 0 ? void 0 : contentRef.current; var _a = useState({}), boxStyles = _a[0], seBoxStyles = _a[1]; var _b = useState({}), contentStyles = _b[0], setContentStyles = _b[1]; var _c = useState(0), contentTop = _c[0], setContentTop = _c[1]; var _d = useState(0), contentHeight = _d[0], setContentHeight = _d[1]; var _e = useState(0), boxTop = _e[0], setBoxTop = _e[1]; var containerRef = useRef(null); // 滚动监听器 var scrollHandler = useCallback(function () { var _a, _b, _c; var currentBoxTop = (_a = boxElement === null || boxElement === void 0 ? void 0 : boxElement.getBoundingClientRect()) === null || _a === void 0 ? void 0 : _a.top; var currentContentTop = (_b = contentElement === null || contentElement === void 0 ? void 0 : contentElement.getBoundingClientRect()) === null || _b === void 0 ? void 0 : _b.top; var currentContentHeight = (_c = contentElement === null || contentElement === void 0 ? void 0 : contentElement.getBoundingClientRect()) === null || _c === void 0 ? void 0 : _c.height; setBoxTop(currentBoxTop || 0); setContentTop(currentContentTop || 0); setContentHeight(currentContentHeight || 0); }, [boxElement, contentElement]); /** * 用于处理content变成fixed定位脱离文档流,导致父级box高度为0 */ useLayoutEffect(function () { var _a; seBoxStyles({ height: (_a = contentElement === null || contentElement === void 0 ? void 0 : contentElement.getBoundingClientRect()) === null || _a === void 0 ? void 0 : _a.height, }); }, [contentElement]); useEffect(function () { containerRef.current = getScrollContainer(container); }, [container]); useLayoutEffect(function () { var _a, _b, _c, _d; var style = { zIndex: zIndex, }; var isFixed = false; if (disabled) return style; var offsetTopNum = Number(offsetTop); if (containerRef.current) { var containerTop = (_b = (_a = containerRef.current) === null || _a === void 0 ? void 0 : _a.getBoundingClientRect()) === null || _b === void 0 ? void 0 : _b.top; var containerHeight = (_d = (_c = containerRef.current) === null || _c === void 0 ? void 0 : _c.getBoundingClientRect()) === null || _d === void 0 ? void 0 : _d.height; if (containerHeight + containerTop < offsetTopNum + contentHeight) { style.transform = "translate3d(0, ".concat(containerHeight - contentHeight, "px, 0)"); } else if (boxTop <= offsetTopNum) { style.position = 'fixed'; style.top = "".concat(offsetTopNum, "px"); isFixed = true; } } else if (boxTop <= offsetTopNum) { style.position = 'fixed'; style.top = "".concat(offsetTopNum, "px"); isFixed = true; } onAffix && onAffix({ scrollTop: contentTop, isFixed: isFixed }); setContentStyles(style); // 这里只需要监听boxTop,不需要全部监听 // eslint-disable-next-line react-hooks/exhaustive-deps }, [boxTop]); useEffect(function () { addEventListener('scroll', scrollHandler); return function () { removeEventListener('scroll', scrollHandler); }; }, [boxTop, contentTop, contentHeight, scrollHandler]); return withNativeProps(prop, React.createElement("div", { "data-testid": "cn-affix", ref: boxRef, className: "cn-ui-m-affix", style: boxStyles }, React.createElement("div", { ref: contentRef, className: "cn-ui-m-affix-content", style: contentStyles }, children))); }; CnAffix.displayName = 'CnAffix'; CnAffix.defaultProps = { container: 'body', disabled: false, offsetTop: 0, zIndex: 99, };