// src/views/Community/components/DynamicNewsCard/VirtualizedFourRowGrid.js // 四列纵向滚动虚拟化网格组件(每行4列,纵向滚动 + 无限滚动) import React, { useRef, useMemo, useEffect } from 'react'; import { useVirtualizer } from '@tanstack/react-virtual'; import { Box, Grid, Spinner, Text, VStack, Center } from '@chakra-ui/react'; import { useColorModeValue } from '@chakra-ui/react'; import DynamicNewsEventCard from '../EventCard/DynamicNewsEventCard'; /** * 四列纵向滚动虚拟化网格组件(支持无限滚动) * @param {Object} props * @param {Array} props.events - 事件列表(累积显示) * @param {Object} props.selectedEvent - 当前选中的事件 * @param {Function} props.onEventSelect - 事件选择回调 * @param {Object} props.eventFollowStatus - 事件关注状态 * @param {Function} props.onToggleFollow - 关注切换回调 * @param {Function} props.getTimelineBoxStyle - 时间轴样式获取函数 * @param {string} props.borderColor - 边框颜色 * @param {Function} props.loadNextPage - 加载下一页(无限滚动) * @param {boolean} props.hasMore - 是否还有更多数据 * @param {boolean} props.loading - 加载状态 */ const VirtualizedFourRowGrid = ({ events, selectedEvent, onEventSelect, eventFollowStatus, onToggleFollow, getTimelineBoxStyle, borderColor, loadNextPage, hasMore, loading, }) => { const parentRef = useRef(null); const isLoadingMore = useRef(false); // 防止重复加载 // 滚动条颜色(主题适配) const scrollbarTrackBg = useColorModeValue('#f1f1f1', '#2D3748'); const scrollbarThumbBg = useColorModeValue('#888', '#4A5568'); const scrollbarThumbHoverBg = useColorModeValue('#555', '#718096'); // 将事件按4个一组分成行(每行4列) const rows = useMemo(() => { const r = []; for (let i = 0; i < events.length; i += 4) { r.push(events.slice(i, i + 4)); } return r; }, [events]); // 配置虚拟滚动器(纵向滚动 + 动态高度测量) const rowVirtualizer = useVirtualizer({ count: rows.length, getScrollElement: () => parentRef.current, estimateSize: () => 250, // 提供初始估算值,库会自动测量实际高度 overscan: 2, // 预加载2行(上下各1行) }); // 无限滚动逻辑 - 监听滚动事件,到达底部时加载下一页 useEffect(() => { const scrollElement = parentRef.current; if (!scrollElement || !loadNextPage) return; const handleScroll = async () => { // 防止重复触发 if (isLoadingMore.current || !hasMore || loading) return; const { scrollTop, scrollHeight, clientHeight } = scrollElement; const scrollPercentage = (scrollTop + clientHeight) / scrollHeight; // 滚动到 80% 时开始加载下一页 if (scrollPercentage > 0.8) { console.log('%c📜 [无限滚动] 到达底部,加载下一页', 'color: #8B5CF6; font-weight: bold;'); isLoadingMore.current = true; await loadNextPage(); isLoadingMore.current = false; } }; scrollElement.addEventListener('scroll', handleScroll); return () => scrollElement.removeEventListener('scroll', handleScroll); }, [loadNextPage, hasMore, loading]); // 底部加载指示器 const renderLoadingIndicator = () => { if (!hasMore) { return (