feat: 虚拟化网格组件通用化 │ │

│ │                                                                                                                                                   │ │
│ │ - 支持多列布局(columnsPerRow 参数,默认4列)                                                                                                     │ │
│ │ - 支持自定义卡片组件(CardComponent 参数)                                                                                                        │ │
│ │ - 根据列数动态调整间距(单列 gap=3,多列 gap=4)                                                                                                  │ │
│ │ - 更新注释和文档
This commit is contained in:
zdl
2025-11-05 08:53:07 +08:00
parent de1b31c70e
commit be0c53b588

View File

@@ -1,5 +1,5 @@
// src/views/Community/components/DynamicNewsCard/VirtualizedFourRowGrid.js
// 四列纵向滚动虚拟化网格组件(每行4列纵向滚动 + 无限滚动)
// 虚拟化网格组件(支持多列布局 + 纵向滚动 + 无限滚动)
import React, { useRef, useMemo, useEffect } from 'react';
import { useVirtualizer } from '@tanstack/react-virtual';
@@ -8,9 +8,11 @@ import { useColorModeValue } from '@chakra-ui/react';
import DynamicNewsEventCard from '../EventCard/DynamicNewsEventCard';
/**
* 四列纵向滚动虚拟化网格组件(支持无限滚动)
* 虚拟化网格组件(支持多列布局 + 无限滚动)
* @param {Object} props
* @param {Array} props.events - 事件列表(累积显示)
* @param {number} props.columnsPerRow - 每行列数(默认 4单列模式传 1
* @param {React.Component} props.CardComponent - 卡片组件(默认 DynamicNewsEventCard
* @param {Object} props.selectedEvent - 当前选中的事件
* @param {Function} props.onEventSelect - 事件选择回调
* @param {Object} props.eventFollowStatus - 事件关注状态
@@ -23,6 +25,8 @@ import DynamicNewsEventCard from '../EventCard/DynamicNewsEventCard';
*/
const VirtualizedFourRowGrid = ({
events,
columnsPerRow = 4,
CardComponent = DynamicNewsEventCard,
selectedEvent,
onEventSelect,
eventFollowStatus,
@@ -41,14 +45,14 @@ const VirtualizedFourRowGrid = ({
const scrollbarThumbBg = useColorModeValue('#888', '#4A5568');
const scrollbarThumbHoverBg = useColorModeValue('#555', '#718096');
// 将事件按4个一组分成行每行4列
// 将事件按 columnsPerRow 个一组分成行
const rows = useMemo(() => {
const r = [];
for (let i = 0; i < events.length; i += 4) {
r.push(events.slice(i, i + 4));
for (let i = 0; i < events.length; i += columnsPerRow) {
r.push(events.slice(i, i + columnsPerRow));
}
return r;
}, [events]);
}, [events, columnsPerRow]);
// 配置虚拟滚动器(纵向滚动 + 动态高度测量)
const rowVirtualizer = useVirtualizer({
@@ -159,17 +163,17 @@ const VirtualizedFourRowGrid = ({
w="100%"
transform={`translateY(${virtualRow.start}px)`}
>
{/* 每行使用 Grid 横向排列4个卡片 */}
{/* 使用 Grid 横向排列卡片(列数由 columnsPerRow 决定) */}
<Grid
templateColumns="repeat(4, 1fr)"
gap={4}
templateColumns={`repeat(${columnsPerRow}, 1fr)`}
gap={columnsPerRow === 1 ? 3 : 4}
w="100%"
>
{rowEvents.map((event, colIndex) => (
<Box key={event.id}>
<DynamicNewsEventCard
<CardComponent
event={event}
index={virtualRow.index * 4 + colIndex}
index={virtualRow.index * columnsPerRow + colIndex}
isFollowing={eventFollowStatus[event.id]?.isFollowing || false}
followerCount={eventFollowStatus[event.id]?.followerCount || event.follower_count || 0}
isSelected={selectedEvent?.id === event.id}
@@ -182,7 +186,7 @@ const VirtualizedFourRowGrid = ({
onEventSelect(event);
}}
onToggleFollow={() => onToggleFollow?.(event.id)}
timelineStyle={getTimelineBoxStyle()}
timelineStyle={getTimelineBoxStyle?.()}
borderColor={borderColor}
/>
</Box>