feat: 首页更新
This commit is contained in:
112
pages/HomeScreen/components/GameMainMenus/index.tsx
Normal file
112
pages/HomeScreen/components/GameMainMenus/index.tsx
Normal file
@@ -0,0 +1,112 @@
|
||||
/**
|
||||
* 游戏分类菜单组件
|
||||
*
|
||||
* 展示游戏分类,支持切换,使用真实数据
|
||||
*/
|
||||
|
||||
import React, { useRef, useEffect, useState, useCallback, useMemo } from 'react';
|
||||
import { View, Text, ScrollView, TouchableOpacity, Animated } from 'react-native';
|
||||
// import type { GameCategory } from '@/types/home';
|
||||
import { styles } from './styles';
|
||||
import { useGameMainMenus, useMenuDataLoaded } from '@/hooks/useGameMenus';
|
||||
// import useGameStore from '@/stores/gameStore';
|
||||
import { ThemeEnum } from '@/constants/theme';
|
||||
|
||||
|
||||
|
||||
interface GameMainMenuProps {
|
||||
theme: ThemeEnum;
|
||||
selectedCategory?: string;
|
||||
onCategorySelect?: (categoryId: string) => void;
|
||||
topHeight?: number;
|
||||
showSubMenus?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* 游戏分类菜单组件
|
||||
*/
|
||||
export default function GameMainMenu({
|
||||
theme,
|
||||
selectedCategory = '103',
|
||||
onCategorySelect,
|
||||
topHeight = 0,
|
||||
showSubMenus = true,
|
||||
}: GameMainMenuProps) {
|
||||
const s = styles[theme];
|
||||
const scrollViewRef = useRef<ScrollView>(null);
|
||||
const gameMenus = useGameMainMenus(theme);
|
||||
|
||||
// 检查数据加载完成
|
||||
const isDataLoaded = useMenuDataLoaded();
|
||||
|
||||
// 使用 useMemo 缓存找到的索引,避免每次都重新计算
|
||||
const selectedIndex = useMemo(() => {
|
||||
return gameMenus.findIndex((cat) => cat.key === selectedCategory);
|
||||
}, [selectedCategory, gameMenus]);
|
||||
|
||||
// 当分类改变时,滚动到该分类
|
||||
useEffect(() => {
|
||||
if (selectedIndex >= 0) {
|
||||
scrollViewRef.current?.scrollTo({
|
||||
x: selectedIndex * 100,
|
||||
animated: true,
|
||||
});
|
||||
}
|
||||
}, [selectedIndex]);
|
||||
|
||||
// 使用 useCallback 稳定 onPress 回调
|
||||
const handleCategoryPress = useCallback((categoryKey: string) => {
|
||||
onCategorySelect?.(categoryKey);
|
||||
}, [onCategorySelect]);
|
||||
|
||||
// 骨架屏 - 显示加载中的占位符
|
||||
const renderSkeleton = () => (
|
||||
<View style={s.container}>
|
||||
<ScrollView
|
||||
style={s.scrollView}
|
||||
horizontal
|
||||
showsHorizontalScrollIndicator={false}
|
||||
scrollEventThrottle={16}
|
||||
>
|
||||
{[1, 2, 3, 4, 5].map((index) => (
|
||||
<View
|
||||
key={`skeleton-${index}`}
|
||||
style={[s.categoryItem, { backgroundColor: theme === 'dark' ? '#333' : '#e0e0e0' }]}
|
||||
/>
|
||||
))}
|
||||
</ScrollView>
|
||||
</View>
|
||||
);
|
||||
|
||||
// 如果动态数据还未加载,显示骨架屏
|
||||
if (!isDataLoaded) {
|
||||
return renderSkeleton();
|
||||
}
|
||||
|
||||
return (
|
||||
<View style={s.container}>
|
||||
<ScrollView
|
||||
ref={scrollViewRef}
|
||||
style={s.scrollView}
|
||||
horizontal
|
||||
showsHorizontalScrollIndicator={false}
|
||||
scrollEventThrottle={16}
|
||||
>
|
||||
{gameMenus.map((menu) => (
|
||||
<TouchableOpacity
|
||||
key={menu.key}
|
||||
style={[s.menuItem, selectedCategory === menu.key && s.menuItemActive]}
|
||||
onPress={() => handleCategoryPress(menu.key)}
|
||||
activeOpacity={0.7}
|
||||
>
|
||||
<Text
|
||||
style={[s.menuText, selectedCategory === menu.key && s.menuTextActive]}
|
||||
>
|
||||
{menu.icon || '🎮'} {menu.name}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
))}
|
||||
</ScrollView>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
47
pages/HomeScreen/components/GameMainMenus/styles.ts
Normal file
47
pages/HomeScreen/components/GameMainMenus/styles.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
import { createThemeStyles } from '@/theme';
|
||||
import { Dimensions } from 'react-native';
|
||||
|
||||
// const { width } = Dimensions.get('window');
|
||||
// const BANNER_HEIGHT = width * 0.32534; // 保持 32.534% 的宽高比
|
||||
|
||||
/**
|
||||
* 创建主题样式
|
||||
*/
|
||||
export const styles = createThemeStyles((colors) => ({
|
||||
container: {
|
||||
backgroundColor: colors.background,
|
||||
paddingVertical: 10,
|
||||
borderBottomWidth: 1,
|
||||
borderBottomColor: colors.border,
|
||||
},
|
||||
scrollView: {
|
||||
paddingHorizontal: 12,
|
||||
},
|
||||
menuItem: {
|
||||
paddingHorizontal: 16,
|
||||
paddingVertical: 10,
|
||||
marginRight: 8,
|
||||
borderRadius: 22,
|
||||
backgroundColor: colors.backgroundSecondary,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
elevation: 1,
|
||||
shadowColor: colors.cardShadow,
|
||||
shadowOffset: { width: 0, height: 1 },
|
||||
shadowOpacity: 0.1,
|
||||
shadowRadius: 2,
|
||||
},
|
||||
menuItemActive: {
|
||||
backgroundColor: colors.primary,
|
||||
elevation: 2,
|
||||
shadowOpacity: 0.15,
|
||||
},
|
||||
menuText: {
|
||||
fontSize: 13,
|
||||
color: colors.text,
|
||||
fontWeight: '600',
|
||||
},
|
||||
menuTextActive: {
|
||||
color: '#FFFFFF',
|
||||
},
|
||||
}));
|
||||
Reference in New Issue
Block a user