@cainiaofe/cn-ui-m
Version:
89 lines (88 loc) • 4.53 kB
JavaScript
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,
};