UNPKG

ahooks

Version:
132 lines 4.4 kB
import { __read } from "tslib"; import { useEffect, useMemo, useState, useRef } from 'react'; import useEventListener from '../useEventListener'; import useLatest from '../useLatest'; import useMemoizedFn from '../useMemoizedFn'; import useSize from '../useSize'; import { getTargetElement } from '../utils/domTarget'; import { isNumber } from '../utils'; import useUpdateEffect from '../useUpdateEffect'; var useVirtualList = function (list, options) { var containerTarget = options.containerTarget, wrapperTarget = options.wrapperTarget, itemHeight = options.itemHeight, _a = options.overscan, overscan = _a === void 0 ? 5 : _a; var itemHeightRef = useLatest(itemHeight); var size = useSize(containerTarget); var scrollTriggerByScrollToFunc = useRef(false); var _b = __read(useState([]), 2), targetList = _b[0], setTargetList = _b[1]; var _c = __read(useState({}), 2), wrapperStyle = _c[0], setWrapperStyle = _c[1]; var getVisibleCount = function (containerHeight, fromIndex) { if (isNumber(itemHeightRef.current)) { return Math.ceil(containerHeight / itemHeightRef.current); } var sum = 0; var endIndex = 0; for (var i = fromIndex; i < list.length; i++) { var height = itemHeightRef.current(i, list[i]); sum += height; endIndex = i; if (sum >= containerHeight) { break; } } return endIndex - fromIndex; }; var getOffset = function (scrollTop) { if (isNumber(itemHeightRef.current)) { return Math.floor(scrollTop / itemHeightRef.current) + 1; } var sum = 0; var offset = 0; for (var i = 0; i < list.length; i++) { var height = itemHeightRef.current(i, list[i]); sum += height; if (sum >= scrollTop) { offset = i; break; } } return offset + 1; }; // 获取上部高度 var getDistanceTop = function (index) { if (isNumber(itemHeightRef.current)) { var height_1 = index * itemHeightRef.current; return height_1; } var height = list.slice(0, index).reduce(function (sum, _, i) { return sum + itemHeightRef.current(i, list[i]); }, 0); return height; }; var totalHeight = useMemo(function () { if (isNumber(itemHeightRef.current)) { return list.length * itemHeightRef.current; } return list.reduce(function (sum, _, index) { return sum + itemHeightRef.current(index, list[index]); }, 0); }, [list]); var calculateRange = function () { var container = getTargetElement(containerTarget); if (container) { var scrollTop = container.scrollTop, clientHeight = container.clientHeight; var offset = getOffset(scrollTop); var visibleCount = getVisibleCount(clientHeight, offset); var start_1 = Math.max(0, offset - overscan); var end = Math.min(list.length, offset + visibleCount + overscan); var offsetTop = getDistanceTop(start_1); setWrapperStyle({ height: totalHeight - offsetTop + 'px', marginTop: offsetTop + 'px' }); setTargetList(list.slice(start_1, end).map(function (ele, index) { return { data: ele, index: index + start_1 }; })); } }; useUpdateEffect(function () { var wrapper = getTargetElement(wrapperTarget); if (wrapper) { Object.keys(wrapperStyle).forEach(function (key) { return wrapper.style[key] = wrapperStyle[key]; }); } }, [wrapperStyle]); useEffect(function () { if (!(size === null || size === void 0 ? void 0 : size.width) || !(size === null || size === void 0 ? void 0 : size.height)) { return; } calculateRange(); }, [size === null || size === void 0 ? void 0 : size.width, size === null || size === void 0 ? void 0 : size.height, list]); useEventListener('scroll', function (e) { if (scrollTriggerByScrollToFunc.current) { scrollTriggerByScrollToFunc.current = false; return; } e.preventDefault(); calculateRange(); }, { target: containerTarget }); var scrollTo = function (index) { var container = getTargetElement(containerTarget); if (container) { scrollTriggerByScrollToFunc.current = true; container.scrollTop = getDistanceTop(index); calculateRange(); } }; return [targetList, useMemoizedFn(scrollTo)]; }; export default useVirtualList;