fix: calc scrollheight dynamically for tabs change
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import { useCallback } from 'react';
|
||||
import { useMemoizedFn } from 'ahooks';
|
||||
import { useCallback, useRef, useState } from 'react';
|
||||
|
||||
interface ScrollOptions {
|
||||
wait?: number;
|
||||
@@ -12,14 +13,27 @@ export default function useScrollAfterExpand({
|
||||
activeKey,
|
||||
setActiveKey,
|
||||
segmentOptions,
|
||||
defaultWait = 300
|
||||
defaultWait = 300,
|
||||
segmentedTop = { top: 0, offsetTop: 96 },
|
||||
getScrollElementScrollableHeight
|
||||
}: {
|
||||
form: any;
|
||||
activeKey: string[];
|
||||
setActiveKey: React.Dispatch<React.SetStateAction<string[]>>;
|
||||
segmentOptions: { value: string; field: string }[];
|
||||
getScrollElementScrollableHeight?: () => {
|
||||
scrollHeight: number;
|
||||
scrollTop: number;
|
||||
};
|
||||
defaultWait?: number;
|
||||
segmentedTop: {
|
||||
top: number;
|
||||
offsetTop: number;
|
||||
};
|
||||
}) {
|
||||
const [holderHeight, setHolderHeight] = useState<number>(0);
|
||||
const boxHeightRef = useRef<number>(0);
|
||||
|
||||
const scrollToElement = useCallback(
|
||||
(
|
||||
el: HTMLElement,
|
||||
@@ -46,7 +60,11 @@ export default function useScrollAfterExpand({
|
||||
[]
|
||||
);
|
||||
|
||||
const scrollToSegment = useCallback(
|
||||
/**
|
||||
* due to the scrollheight changes after expanding the segment and including the holder height.
|
||||
*
|
||||
*/
|
||||
const scrollToSegment = useMemoizedFn(
|
||||
async (val: string, options?: ScrollOptions) => {
|
||||
if (!activeKey.includes(val)) {
|
||||
setActiveKey((prev) => [...prev, val]);
|
||||
@@ -55,19 +73,48 @@ export default function useScrollAfterExpand({
|
||||
});
|
||||
}
|
||||
|
||||
await new Promise(requestAnimationFrame);
|
||||
|
||||
const current = segmentOptions.find((item) => item.value === val);
|
||||
if (!current?.field) return;
|
||||
|
||||
const el = document.querySelector(
|
||||
await new Promise(requestAnimationFrame);
|
||||
|
||||
const el: HTMLElement | null = document.querySelector(
|
||||
`[data-field="${current.field}"]`
|
||||
) as HTMLElement | null;
|
||||
|
||||
const targetRectTop = el?.getBoundingClientRect().top || 0;
|
||||
|
||||
const scroller = getScrollElementScrollableHeight?.() || {
|
||||
scrollHeight: 0,
|
||||
scrollTop: 0
|
||||
};
|
||||
|
||||
// remaining scroll height
|
||||
const remainingScrollHeight = scroller.scrollHeight - scroller.scrollTop;
|
||||
|
||||
// total distance from the top of the scroller to the target element
|
||||
const offsetDistance =
|
||||
targetRectTop - segmentedTop.offsetTop - segmentedTop.top;
|
||||
|
||||
let boxHeight = 0;
|
||||
|
||||
// verify boxHeight is correct, if setting the boxHeight causes the element to be hidden, use the previous boxHeight
|
||||
if (offsetDistance <= 0) {
|
||||
boxHeight = boxHeightRef.current;
|
||||
} else {
|
||||
boxHeight =
|
||||
offsetDistance - remainingScrollHeight + boxHeightRef.current;
|
||||
}
|
||||
|
||||
// update boxHeightRef
|
||||
boxHeightRef.current = boxHeight;
|
||||
|
||||
setHolderHeight(boxHeight);
|
||||
await new Promise(requestAnimationFrame);
|
||||
|
||||
if (el) scrollToElement(el, options);
|
||||
},
|
||||
[activeKey, setActiveKey, segmentOptions, defaultWait, scrollToElement]
|
||||
}
|
||||
);
|
||||
|
||||
return { scrollToSegment };
|
||||
return { scrollToSegment, holderHeight };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user